SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-10-21

SQLite في الإنتاج على VPS: الإعداد والحدود

اكتشف لماذا تناسب SQLite معظم التطبيقات الصغيرة على VPS واحد، وكيف تضبط WAL وbusy_timeout وتستخدم Litestream، ومتى تصبح SQLite عنق زجاجة.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

متى تكون SQLite قاعدة البيانات الإنتاجية المناسبة على VPS

يُعد تشغيل SQLite في بيئة الإنتاج على VPS الخيار المناسب لمعظم التطبيقات الصغيرة، والسبب بسيط: العملية الواحدة على الجهاز الواحد التي تكتب في ملف واحد لا تحتاج إلى خادم قاعدة بيانات. لا توجد خدمة خفية تحتاج إلى مراقبة، ولا منفذ يحتاج إلى إعداد قاعدة جدار ناري، ولا كلمة مرور تحتاج إلى تدويرها، ولا جهاز ثانٍ يجب إبقاؤه قيد التشغيل. الاستعلام عبارة عن استدعاء دالة بدلاً من رحلة ذهاب وإياب عبر الشبكة، لذلك فإن الصفحة التي تنفذ أربعين استعلاماً تكلّفك أربعين استدعاء دالة.

التكلفة محدودة وحقيقية. تسمح SQLite بكاتب واحد في كل مرة على مستوى ملف قاعدة البيانات بالكامل، ولا يمكن مشاركة الملف بين جهازين. كلا القيدين مناسب لـVPS واحد يشغّل تطبيقاً واحداً. لكنهما يصبحان مانعين فور تجاوزك هذا الشكل. يغطي هذا الدليل الإعدادات التي تجعل SQLite آمنة على الخادم، والنسخ الاحتياطي المستمر باستخدام Litestream، والنقطة التي ينبغي عندها التوقف عن استخدامها.

ثبّت أداة سطر الأوامر أولاً. نُفِّذت جميع الخطوات أدناه على Ubuntu 24.04.

sudo apt update
sudo apt install -y sqlite3
sqlite3 --version

يطبع ذلك إصداراً يبدأ بـ3.، تتبعه جهة بناء وتجزئة مصدر. توفّر Ubuntu 24.04 إصدار SQLite 3.45.1 اعتباراً من October 2026. من المحتمل أن تطبيقك لا يستخدم هذه الثنائية: إذ تضمّن معظم أوقات تشغيل اللغات نسختها الخاصة من مكتبة SQLite، وغالباً ما تكون أحدث منها، لذلك تحقّق من الإصدار الذي يعرضه مشغّل قاعدة البيانات لديك قبل الاعتماد على ميزة حديثة.

لماذا يكون وضع WAL أول ما تغيّره

يستخدم SQLite دفتر تراجع في الإعداد الافتراضي. قبل تغيير صفحة، ينسخ الصفحة الأصلية إلى ملف -journal، ثم يعدّل قاعدة البيانات في مكانها. ولتنفيذ ذلك بأمان، يحصل على قفل حصري للملف بأكمله، لذلك ينتظر كل قارئ أثناء تنفيذ أي عملية كتابة. لا يلاحظ أحد ذلك على حاسوب محمول. أما على خادم ويب، فتؤدي كتابة بطيئة واحدة إلى إيقاف كل طلب يتعامل مع قاعدة البيانات.

يعكس وضع WAL ‏(سجل الكتابة المسبقة) هذا الترتيب. يضيف الكاتب الصفحات الجديدة إلى ملف -wal منفصل، ويترك قاعدة البيانات الرئيسية دون تغيير. يواصل القراء قراءة الملف الرئيسي وفق اللقطة التي بدأوا بها، لذلك لا يحجب القراء الكاتب، ولا يحجب الكاتب القراء. لاحقاً، تنسخ نقطة تحقق صفحات WAL المتراكمة إلى قاعدة البيانات الرئيسية. هذا التغيير وحده هو العامل الأكبر الذي يجعل SQLite قابلاً للاستخدام خلف تطبيق ويب.

فعّل وضع WAL وتحقق من بقائه

mkdir -p ~/app
sqlite3 ~/app/app.db "PRAGMA journal_mode=WAL;"

يطبع الأمر wal. هذا الناتج ليس للزينة. يعرض PRAGMA journal_mode الوضع الفعلي لقاعدة البيانات، لذلك تعني الإجابة delete أن التغيير فشل وأنك ما زلت تستخدم سجل التراجع.

وضع WAL مستمر. فهو علامة في ترويسة قاعدة البيانات، وليس إعداداً للاتصال. لذلك تشغّله مرة واحدة لكل ملف قاعدة بيانات، وترثه جميع الاتصالات اللاحقة، بما في ذلك بعد إعادة التشغيل. أثبت ذلك باستخدام اتصال جديد.

sqlite3 ~/app/app.db "PRAGMA journal_mode;"

أنشئ الآن جدولاً وانظر إلى ما يظهر على القرص.

sqlite3 ~/app/app.db <<'SQL'
CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT NOT NULL);
INSERT INTO notes (body) VALUES ('first row');
SQL
ls -l ~/app/

توجد الآن ثلاثة ملفات: app.db وapp.db-wal وapp.db-shm. يحتوي الملف -wal على الصفحات التي تم اعتمادها ولم تُنفَّذ لها عملية checkpoint بعد. أما الملف -shm فهو فهرس للذاكرة المشتركة تربطه كل الاتصالات حتى تتفق جميعاً على محتوى WAL. ينتمي الملفان إلى قاعدة البيانات، وليسا ملفين مؤقتين. إذا نسخت app.db وحده أثناء تشغيل التطبيق، فستحصل على ملف يفتقد كل عمليات الاعتماد الأخيرة. وإذا حذفت app.db وتركت الملفين الآخرين، فسيطبّق SQLite صفحات WAL القديمة على أي ملف جديد يظهر بهذا الاسم. هكذا تتلف قواعد بيانات جديدة عند محاولة إعادة ضبط قاعدة بيانات.

إعدادات الاتصال التي يحتاجها كل تطبيق في بيئة الإنتاج

يُخزَّن journal_mode فقط في قاعدة البيانات. أما كل إعداد آخر أدناه فهو خاص بالاتصال، ما يعني أن على تطبيقك تنفيذه عند كل اتصال يفتحه، بما في ذلك كل اتصال ينشئه connection pool في الخلفية.

PRAGMA journal_mode = WAL;
PRAGMA busy_timeout = 5000;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;

يخبر busy_timeout = 5000 SQLite بإعادة المحاولة عند قفل قاعدة البيانات لمدة تصل إلى 5000 ميلي ثانية قبل أن يعيد database is locked. القيمة الافتراضية هي 0، لذلك يفشل SQLite فوراً في المرة الأولى التي تتداخل فيها عمليتا كتابة. ويزيل ضبط هذه القيمة الوحيدة معظم أخطاء القفل التي تُنسب إلى SQLite نفسه.

يُعد synchronous = NORMAL الإعداد المناسب في وضع WAL، ومن المهم فهم المقابل لذلك. عند ضبط FULL، يستدعي SQLite fsync على WAL عند كل عملية commit. أما عند ضبط NORMAL، فيجري المزامنة عند نقاط checkpoint بدلاً من ذلك. توضح وثائق SQLite بصرامة ما تتخلى عنه: لا تعود المعاملات متينة بعد انقطاع الطاقة أو إعادة الضبط القسري. لا يمكن لانقطاع الطاقة هذا إفساد قاعدة البيانات، لكنك ستفقد آخر عمليات commit التي لم تصل إلى القرص. على VPS، يكون هذا المقابل مناسباً عادةً، لأنه يزيل fsync من مسار كل عملية كتابة.

يكون foreign_keys = ON معطلاً افتراضياً للحفاظ على التوافق مع الإصدارات السابقة، وهو خاص بكل اتصال. ولا يفرض مخطط يحتوي على عبارات REFERENCES أي شيء على الإطلاق إلى أن يفعّل كل اتصال هذا الإعداد.

هناك إعداد آخر لا تبرز أهميته إلا لاحقاً. ينفّذ SQLite checkpoint تلقائياً عندما يتجاوز حجم WAL 1000 صفحة، وتنفّذ العملَ أيُّ connection تنتهي مصادفةً من معاملة في تلك اللحظة. لا توجد مشكلة في ذلك بحد ذاته. لكنه يصبح موضعاً للنقاش عند تشغيل Litestream، لأن Litestream يريد التحكم في توقيت تنفيذ نقاط checkpoint.

لماذا لا يزال database is locked يحدث بعد ضبط busy_timeout

هذا هو الفشل الذي يعيد المستخدمين إلى Postgres، وله سبب محدد واحد.

يُثبّت مهلة الانشغال معالجاً للانشغال، لكن SQLite لا يضمن استدعاءه.

إذا حدّد SQLite أن استدعاء معالج الانشغال قد يؤدي إلى حالة جمود، فسيعيد SQLITE_BUSY إلى التطبيق مباشرة بدلاً من استدعاء معالج الانشغال.

يحدث الجمود الذي يتجنبه SQLite عند ترقية المعاملة. يعني BEGIN المجرد في SQLite: BEGIN DEFERRED. إذا كانت العبارة الأولى بعده هي SELECT، فأنت داخل معاملة قراءة. عندما تحتاج UPDATE لاحقة في المعاملة نفسها إلى التحول إلى معاملة كتابة، وتكون وصلة أخرى قد أجرت كتابة منذ بدء قراءتك، لا يستطيع SQLite أن يجعلك تنتظر، لأن اللقطة التي تقرؤها أصبحت قديمة، والانتظار سيؤدي فقط إلى إدخال الوصلتين في حالة جمود متبادل. يوضح التوثيق النتيجة مباشرة:

ستُرقي عبارات الكتابة اللاحقة المعاملة إلى معاملة كتابة إن أمكن، أو ستعيد SQLITE_BUSY.

لا تُستخدم مهلة 5000 ميلي ثانية مطلقاً. يصل الخطأ فوراً، ولذلك يبدو كأن الإعداد لم يفعل شيئاً.

الإصلاح يتكون من كلمة واحدة.

BEGIN IMMEDIATE;
UPDATE notes SET body = 'edited' WHERE id = 1;
COMMIT;

تأخذ BEGIN IMMEDIATE قفل الكتابة في البداية، قبل قراءة أي شيء. لا تحدث ترقية، ولذلك لا يوجد جمود يجب تجنبه، ويُطبَّق معالج الانشغال، فتنتظر الوصلة دورها بدلاً من الفشل. أبقِ معاملات القراءة للوقت المؤجل. يجب أن تكون أي معاملة تتضمن كتابة فورية.

السبب الثاني لأخطاء القفل أصعب اكتشافاً: إبقاء معاملة كتابة مفتوحة أثناء تنفيذ عمل بطيء. ينظّم SQLite عمليات الكتابة بالتسلسل، ولذلك ستمنع معاملة تُفتح، ثم تستدعي API خارجية عبر الشبكة، ثم تُجري commit، كل كاتب آخر طوال مدة ذلك الاستدعاء. اقرأ ما تحتاج إليه، ثم أغلق المعاملة، ونفّذ العمل البطيء، وبعد ذلك افتح معاملة كتابة قصيرة لتخزين النتيجة.

النسخ الاحتياطي المستمر باستخدام Litestream

تفقد النسخة الليلية ما يصل إلى يوم كامل من الكتابات، وقد يؤدي تشغيل cp على قاعدة بيانات SQLite قيد الاستخدام إلى إنشاء نسخة لا يمكن فتحها. توجد طريقتان آمنتان. يستخدم sqlite3 app.db ".backup /path/to/backup.db" واجهة النسخ الاحتياطي المباشر في SQLite، ويعمل على قاعدة بيانات قيد الاستخدام. أما Litestream فيتجاوز ذلك: إذ يراقب WAL ويرسل التغييرات إلى التخزين الكائني باستمرار، ما يقلل الحد الأقصى المحتمل لفقدان البيانات من يوم إلى نحو ثانية واحدة.

Litestream ملف ثنائي واحد مكتوب بلغة Go ويعمل بجانب تطبيقك. ولا يقع بين التطبيق وقاعدة البيانات. يكتب تطبيقك إلى SQLite بالطريقة نفسها المعتادة، بينما يقرأ Litestream من WAL ويرفع التغييرات.

cd /tmp
curl -fsSL -O https://github.com/benbjohnson/litestream/releases/download/v0.5.14/litestream-0.5.14-linux-x86_64.deb
sudo dpkg -i litestream-0.5.14-linux-x86_64.deb
litestream version

لا يزال v0.5.14 هو الإصدار الذي توثقه صفحة التثبيت الرسمية لنظام Linux حتى أكتوبر 2026. وقد صدرت إصدارات أحدث: v0.5.15 في 21 يوليو 2026، وv0.5.17، وهو أحدث وسم، في 31 أغسطس 2026. غيّر الإصدار في السطرين ليتوافق مع الوسم الحالي في صفحة الإصدارات، واستخدم حزمة arm64 المطابقة بدلاً منها إذا كان VPS لديك يستخدم arm64.

يوجد ملف الإعداد في /etc/litestream.yml. ابدأ بنسخة محلية، لأن ذلك يثبت عمل الدورة كاملة من دون الحاجة إلى بيانات اعتماد سحابية.

dbs:
  - path: /home/appuser/app/app.db
    replica:
      type: file
      path: /var/backups/litestream/app

لاحظ أن الحقل هو replica بصيغة المفرد. استبدل Litestream 0.5 مصفوفة replicas من سلسلة 0.3 بكتلة نسخة واحدة، وأصبح ملف الإعداد الذي يحتوي على إدخالين يفشل عند بدء التشغيل. لا تزال أدلة كثيرة من جهات خارجية تعرض المصفوفة القديمة، لذلك انسخ البنية أعلاه بدلاً من أول مثال تعرضه نتائج البحث. كما أعادت سلسلة 0.5 تسمية الأمر الفرعي litestream wal إلى litestream ltx، لأن تنسيق النسخ الاحتياطية على القرص تغيّر.

تحقق من إمكانية تحليل ملف الإعداد قبل تفعيل أي شيء.

sudo litestream databases -config /etc/litestream.yml

ثم أثبت عمل الدورة كاملة يدوياً. تتجاوز هذه الصيغة ملف الإعداد، وتنسخ قاعدة بيانات واحدة إلى مسار واحد.

mkdir -p /tmp/replica
litestream replicate ~/app/app.db file:///tmp/replica/app

يعمل ذلك في الواجهة الأمامية ويستمر في التشغيل. في جلسة shell ثانية، اكتب صفاً ثم استعد النسخة إلى ملف جديد.

sqlite3 ~/app/app.db "INSERT INTO notes (body) VALUES ('written after replication started');"
litestream restore -o /tmp/restored.db file:///tmp/replica/app
sqlite3 /tmp/restored.db "SELECT count(*) FROM notes;"

يشمل العدد الصف الجديد. إذا لم يظهر، فهذا يعني أن التغيير لم تتم مزامنته بعد: يدفع Litestream التغييرات وفق sync-interval الذي تكون قيمته الافتراضية 1 ثانية، لذلك انتظر ثم نفّذ الاستعادة مرة أخرى. وتمثل هذه الثانية أيضاً نقطة الاستعادة لديك. عند حدوث عطل، تفقد في أقصى الحالات الكتابات التي تمت خلال فترة المزامنة الأخيرة، ولا يمكن لأي إعداد جعل ذلك صفراً.

بالنسبة إلى التخزين الفعلي، استبدل كتلة النسخة بعنوان S3. يعمل ذلك مع Amazon S3 ومع التخزين الكائني المتوافق مع S3 من موفرين آخرين.

dbs:
  - path: /home/appuser/app/app.db
    replica:
      url: s3://your-bucket-name/app
      region: us-east-1

snapshot:
  interval: 24h
  retention: 24h

لا تضع بيانات الاعتماد في ذلك الملف. يقرأ Litestream LITESTREAM_ACCESS_KEY_ID وLITESTREAM_SECRET_ACCESS_KEY من البيئة، لذلك ضعها في ملف drop-in لـsystemd يملكه root وبصلاحية 600.

القيم المتعلقة باللقطات أعلاه هي القيم الافتراضية، كما أن القيمة الافتراضية للاحتفاظ قد تكون غير متوقعة. يحدد الاحتفاظ المدة التي يحتفظ فيها Litestream باللقطات والملفات التابعة لها، ولذلك يحدد أيضاً المدة التي يمكنك الرجوع إليها عند الاستعادة. تعني أربع وعشرون ساعة أن عملية ترحيل خاطئة تكتشفها صباح الأربعاء تصبح غير قابلة للاستعادة من حالة يوم الاثنين. في Litestream 0.5، يكون الاحتفاظ إعداداً عاماً داخل كتلة snapshot الجذرية، وليس إعداداً لكل نسخة. للاحتفاظ بالنسخ أسبوعاً، غيّر تلك الكتلة إلى retention: 168h وتحمّل تكلفة التخزين الإضافي. ويُعد سطر retention: داخل كتلة النسخة صيغة خاصة بسلسلة 0.3. يتجاهله Litestream 0.5 من دون إظهار خطأ، ويستمر باستخدام القيمة الافتراضية البالغة 24 ساعة.

أثبت صلاحية الاستعادة قبل أن تحتاج إليها

litestream restore -o /tmp/check.db /home/appuser/app/app.db
sqlite3 /tmp/check.db "PRAGMA integrity_check;"
sqlite3 /tmp/check.db "SELECT count(*) FROM notes;"

عند تقديم مسار قاعدة بيانات، يبحث litestream restore عن النسخة المتماثلة المطابقة في /etc/litestream.yml وينزّلها. يطبع PRAGMA integrity_check القيمة ok للملف السليم، وأي مخرجات أخرى تعني أن النسخة المستعادة غير صالحة للاستخدام. شغّل هذا دورياً باستخدام خدمة ومؤقت systemd واقرأ المخرجات. ما لم تستعد نسخة احتياطية مرة واحدة، فلن تعرف أنها تعمل.

تشغيل Litestream باستخدام systemd

تثبّت حزمة Debian وحدة litestream التي تقرأ /etc/litestream.yml.

sudo systemctl enable litestream
sudo systemctl start litestream
sudo journalctl -u litestream -f

يعرض الخرج السليم اسم كل قاعدة بيانات من الإعدادات، ثم يظل هادئاً باستثناء أسطر المزامنة الدورية. يشير الخطأ no such file or directory في مسار قاعدة البيانات إلى أن المسار في الإعدادات غير صحيح، أو إلى أن العملية لا تستطيع قراءته. تعمل الوحدة باستخدام root افتراضياً، وهذا يمنحها صلاحيات أكثر مما تحتاج إليه هذه المهمة. يجب أن يتمكن Litestream من قراءة قاعدة البيانات والدليل الذي يحتوي عليها والكتابة فيهما، لأنه يعمل مع الملفين -wal و-shm الموجودين بجانب قاعدة البيانات. لذلك امنحه حساب المستخدم الذي يعمل التطبيق به، وهو appuser في هذه الأمثلة.

# /etc/systemd/system/litestream.service.d/override.conf
[Service]
User=appuser
Group=appuser

طبّق ذلك باستخدام sudo systemctl daemon-reload وsudo systemctl restart litestream. يستغرق إعداد حساب خدمة مخصص بأقل الصلاحيات بضع دقائق، لكنه يحقق الفرق بين وكيل نسخ احتياطي وعملية root ثانية على الخادم.

هناك تفصيل مهم في ترتيب التشغيل إذا أعدت إنشاء الجهاز من الصفر. يجب استعادة قاعدة البيانات قبل بدء التطبيق. يقبل litestream restore الخيار -if-db-not-exists، الذي يخرج بالرمز 0 عندما يكون الملف موجوداً بالفعل، ولذلك من الآمن تشغيله عند كل إقلاع. ضعه في سطر ExecStartPre ضمن وحدة التطبيق، وعندها يجلب VPS جديد قاعدة البيانات أثناء الإقلاع، بينما لا يفعل الجهاز الموجود شيئاً. يحتوي litestream replicate على الخيار المطابق -restore-if-db-not-exists إذا كنت تفضّل إبقاء ذلك في مكان واحد.

أين تتعطل SQLite على VPS

أنظمة الملفات عبر الشبكة. هذا حد لا يمكنك تجاوزَه بالإعدادات. يتطلب وضع WAL أن تشترك كل عملية تستخدم قاعدة البيانات في منطقة صغيرة من الذاكرة، ويوفّر ملف -shm هذه المنطقة. توضح وثائق SQLite القاعدة دون استثناء:

يجب أن تكون جميع العمليات التي تستخدم قاعدة البيانات على الكمبيوتر المضيف نفسه؛ ولا يعمل WAL عبر نظام ملفات شبكي.

لذلك قد تتعرض قاعدة البيانات الموجودة على مشاركة NFS (نظام ملفات شبكي) أو SMB للفساد، ولا تمنع أي pragma ذلك. توجد هنا نقطة تمييز يغفل عنها بعض المستخدمين. يظهر جهاز كتلي عبر الشبكة، وهو ما يربطه معظم موفري VPS كوحدة تخزين إضافية، لنظام Linux كقرص عادي يحتوي على نظام ملفات عادي، وهذا مناسب. أما مشاركة الملفات المركّبة فمختلفة.

خادم تطبيقات ثانٍ. لا يوجد إعداد يجعل هذا يعمل. عندما تحتاج إلى جهازين يقدمان البيانات نفسها، تحتاج إلى قاعدة بيانات تتواصل عبر الشبكة. قرّر هذا الانتقال ما دمت تملك وقتاً للتخطيط له.

أحمال العمل كثيفة الكتابة. إن وجود كاتب واحد في كل مرة خاصية في تنسيق الملف، وليس إعداداً قابلاً للضبط. تكون عمليات الكتابة القصيرة منخفضة التكلفة لأن كل عملية commit تُضاف إلى WAL، لذلك يعتمد معدل النقل على زمن استجابة القرص للكتابات الصغيرة أكثر من اعتماده على وحدة المعالجة المركزية. راجع NVMe مقارنةً بتخزين SATA SSD على VPS لمعرفة شكل هذا الفرق. المشكلة الفعلية هي المعاملات الطويلة، لأنها تصطف خلفها جميع عمليات الكتابة الأخرى.

الاستعلامات التحليلية. SQLite مخزن صفوف صُمم للمعاملات. أما لوحة المعلومات التي تفحص مئة مليون صف فهي مهمة مختلفة لأداة مختلفة، ويشرح DuckDB مقارنةً بـ SQLite لأعمال الخوادم الحد الفاصل بينهما.

VACUUM أثناء النسخ المتماثل. يعيد VACUUM كتابة ملف قاعدة البيانات بالكامل، وهذا يبطل تتبع مستوى الصفحات الذي يعتمد عليه Litestream. لذلك توصي وثائق Litestream بعدم تشغيله في مكانه أثناء نشاط النسخ المتماثل. وتوصي باستخدام VACUUM INTO، الذي يكتب نسخة مضغوطة إلى ملف منفصل ويترك الملف الأصلي دون تغيير. إذا كان لا بد من تنفيذ vacuum في مكانه، فالإجراء الموثق أطول من إعادة التشغيل: أوقف أداة النسخ المتماثل، ونفّذ vacuum، واحذف دليل التتبع المخفي الخاص بـ Litestream الموجود بجانب قاعدة البيانات وبيانات النسخة المتماثلة البعيدة الموجودة، ثم شغّله مجدداً ليبدأ من لقطة كاملة جديدة. تؤدي الخطوة الأخيرة إلى حذف سجل الاستعادة الذي كان لديك.

أداتا نسخ متماثل لقاعدة بيانات واحدة. لا تشغّل عمليتي Litestream على قاعدة البيانات نفسها أو على وجهة النسخة المتماثلة نفسها. توضح الوثائق صراحةً أن منع ذلك مسؤوليتك، وإلا فستحصل على نسخة متماثلة لا يمكنك استعادتها.

ما لا يغطيه Litestream

يحمي Litestream ملف قاعدة البيانات فقط، ولا يحمي أي شيء آخر. تظل الملفات المرفوعة وإعدادات التطبيق وشهادات TLS (أمان طبقة النقل) وملفات الوحدات ضمن مسؤوليتك. اقرنه بجدولة نسخ احتياطية مشفّرة خارج الخادم باستخدام restic، وبذلك يغطي الحل جانبي الحماية. إذا كان الخادم جديداً، يشرح الدقائق العشر الأولى على VPS جديد إعداد حساب المستخدم وجدار الحماية، ويفترض هذا الدليل أن كليهما أُنجز مسبقاً.

FAQ

هل SQLite كافية لتطبيق يعمل في بيئة الإنتاج؟

لتطبيق واحد على خادم واحد، نعم، بشرط تفعيل وضع WAL، وضبط مهلة انتظار الانشغال، وإجراء نسخ احتياطي مستمر. القيود المهمة هنا بنيوية: كاتب واحد في كل مرة، وجهاز مضيف واحد. إذا كان التطبيق يندرج ضمن هذه الحدود، فستحصل على قاعدة بيانات من دون قفزة شبكية ومن دون عملية منفصلة لمراقبتها. أما إذا تجاوز التطبيق هذه الحدود، فيحتاج إلى قاعدة بيانات بنموذج العميل-الخادم، ولا يمكن لأي قدر من الضبط تغيير ذلك.

لماذا ما زلت أحصل على database is locked بعد ضبط busy_timeout؟

لأن SQLite تتجاوز معالج الانشغال عندما قد يؤدي الانتظار إلى حالة تعارض متبادل. تكون المعاملة التي تبدأ بـ BEGIN مجردة من التأجيل: إذ يضعها SELECT الافتتاحي في معاملة قراءة، ثم يجب على عملية كتابة لاحقة ترقيتها. إذا أجرى اتصال آخر عملية كتابة في هذه الأثناء، تُرجع SQLite SQLITE_BUSY فوراً بدلاً من استدعاء معالج الانشغال، لأن لقطة القراءة لديك أصبحت قديمة. ابدأ أي معاملة ستجري عملية كتابة باستخدام BEGIN IMMEDIATE، حتى يُؤخذ قفل الكتابة مسبقاً وتُطبَّق المهلة.

هل يمكنني الاحتفاظ بقاعدة بيانات SQLite على وحدة تخزين شبكية؟

ليس على نظام ملفات شبكي مثل NFS أو SMB. يحتاج وضع WAL إلى أن تتشارك جميع العمليات الذاكرة عبر ملف -shm، وتنص وثائق SQLite على أن كل عملية تستخدم قاعدة البيانات يجب أن تكون على جهاز مضيف واحد. أما جهاز الكتل الشبكي الذي يرفقه موفّر الخدمة، فهو مختلف: يرى Linux قرصاً عادياً بنظام ملفات عادي، وتعمل SQLite عليه.

هل أحتاج إلى Litestream إذا كنت أجري نسخاً احتياطية ليلية بالفعل؟

يعتمد ذلك على مقدار البيانات الذي يمكنك تحمّل فقدانه. تعني المهمة الليلية فقدان ما يصل إلى أربع وعشرين ساعة من عمليات الكتابة. تزامن Litestream البيانات مرة واحدة تقريباً كل ثانية، لذلك يكلّفك التعطل فقدان الثانية الأخيرة تقريباً. وهو أكثر أماناً أيضاً من نسخ ملف قاعدة البيانات باستخدام cp، لأن ذلك قد يلتقط قاعدة البيانات أثناء عملية كتابة. يغطي Litestream قاعدة البيانات فقط، لذلك أبقِ مهمة نسخ احتياطي عامة للملفات قيد التشغيل إلى جانبه.

هل كان هذا المقال مفيدًا؟

#sqlite#wal#litestream#نسخ احتياطية#production