🌐 Detecting your location…

كيفية ترحيل قاعدة بيانات الإنتاج دون توقف في عام 2026: الدليل الكامل

⏱️2 min read  ·  376 words

نادراً ما تكون الهجرة التي تؤدي إلى انخفاض الإنتاج معقدة. عادة ما يكونALTER TABLEواحد الذي أخذ قفلًا حصريًا على طاولة كبيرة أثناء انتظار التطبيق. يعد الترحيل بدون توقف بمثابة نظام وليس أداة: قم بتقسيم كل تغيير إلى خطوات آمنة بشكل فردي مع تشغيل التعليمات البرمجية القديمة والجديدة في وقت واحد.

المبدأ الأساسي: التوسع والتعاقد

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

يقوم نمط العقد الموسع بتقسيم كل تغيير إلى ثلاث عمليات نشر:

  1. قم بتوسيع – إضافة الهيكل الجديد. يتجاهلها الكود القديم؛ رمز جديد يمكن استخدامه.
  2. ترحيل — ردم البيانات وتحويل التطبيق إلى البنية الجديدة.
  3. العقد – قم بإزالة البنية القديمة بمجرد عدم وجود أي إشارة إليها.

يتم نشر كل خطوة بشكل منفصل، ويمكن عكس كل خطوة على حدة. وهذا ما يجعل التسلسل بأكمله آمنًا.

مثال: إعادة تسمية عمود

تبدو عملية إعادة التسمية تافهة وهي من أخطر العمليات، لأنها تؤدي إلى كسر التعليمات البرمجية القديمة فور تشغيلها.

-- ❌ Never do this on a live system.
ALTER TABLE users RENAME COLUMN email TO email_address;
-- Every running instance still querying "email" fails immediately.

التسلسل الآمن:

-- Step 1 (expand): add the new column. Nullable, no default — instant.
ALTER TABLE users ADD COLUMN email_address TEXT;

-- Step 2: deploy code that WRITES both columns and READS the old one.
--   UPDATE users SET email = $1, email_address = $1 WHERE id = $2

-- Step 3: backfill existing rows in batches (see below).

-- Step 4: deploy code that READS the new column and still writes both.

-- Step 5: deploy code that only uses the new column.

-- Step 6 (contract): drop the old column, once nothing references it.
ALTER TABLE users DROP COLUMN email;

تبدو عمليات النشر الست لإعادة التسمية زائدة عن الحد حتى تؤدي المرة الأولى التي تؤدي فيها عملية إعادة التسمية بخطوة واحدة إلى انقطاع الخدمة. تقرر معظم الفرق في النهاية أن إعادة التسمية لا تستحق العناء وتحتفظ ببساطة بالاسم الأصلي.

ما هي العمليات التي تقفل

إن معرفة أي العبارات تأخذ قفل الحظر هو الجزء الأكبر من المهارة. في PostgreSQL الحديثة:

العملية آمن؟ ملاحظات
إضافة عمود لاغٍ آمنة بيانات التعريف فقط، فورية
أضف عمودًا افتراضيًا ثابتًا آمنة لا توجد إعادة كتابة جدول في الإصدارات الحديثة
أضف عمودًا افتراضيًا متقلبًا خطير يعيد كتابة الجدول بأكمله
أضف فهرس خطير كتل الكتابة – استخدم بشكل متزامن
أضف NOT NULL إلى العمود الموجود خطير فحص كامل تحت القفل — استخدم قيد التحقق أولاً
تغيير نوع العمود خطير عادة إعادة كتابة كاملة
إضافة مفتاح خارجي خطير التحقق من صحة كافة الصفوف — أضف NOT VALID أولاً
إسقاط العمود آمنة بيانات التعريف فقط، ولكنها تكسر الكود القديم

تحقق دائمًا من إصدار قاعدة البيانات المحددة لديك. لقد تحسن سلوك هذه العمليات بشكل كبير مقارنة بالإصدارات الأخيرة، وغالبًا ما تكون النصائح المكتوبة للإصدارات الأقدم حذرة بلا داع – أو قديمة بشكل خطير في الاتجاه الآخر.

إضافة الفهارس بأمان

-- ❌ Blocks all writes to the table for the duration.
CREATE INDEX idx_users_email ON users(email);

-- ✅ Builds without blocking writes.
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);

شيئان يجب معرفتهما عنCONCURRENTLY. لا يمكن تشغيله داخل كتلة المعاملات، مما يعني أن معظم أطر عمل الترحيل تحتاج إلى تكوين صريح للسماح بذلك. ويمكن أن يفشل جزئيًا، مما يؤدي إلى ترك فهرس غير صالح خلفه ويجب تنظيفه.

-- Find invalid indexes left behind by a failed concurrent build
SELECT indexrelid::regclass AS index_name
FROM pg_index
WHERE NOT indisvalid;

-- Drop and retry
DROP INDEX CONCURRENTLY idx_users_email;

إضافة NOT NULL بدون قفل طويل

اضافةNOT NULL يقوم بمسح الجدول بأكمله مباشرةً أثناء الضغط على القفل. يحقق قيد التحقق الذي تم التحقق منه نفس الضمان في خطوتين غير محظورتين.

-- 1. Add the constraint without validating existing rows — instant.
ALTER TABLE users
  ADD CONSTRAINT users_email_not_null
  CHECK (email IS NOT NULL) NOT VALID;

-- 2. Validate separately. Takes a weaker lock that allows reads and writes.
ALTER TABLE users VALIDATE CONSTRAINT users_email_not_null;

ينطبق نفس نمط NOT VALID / VALIDATE على المفاتيح الخارجية، ولنفس السبب.

ردم الطاولات الكبيرة

واحدUPDATE عبر ملايين الصفوف يحمل الأقفال، وينشئ حجمًا هائلاً من سجل الكتابة المسبق، ويمكن أن يوقف النسخ المتماثل. دفعة واحدة.

-- ❌ One statement, one very long transaction, many locked rows.
UPDATE users SET email_address = email;
-- ✅ Batched, resumable, and gentle on replication.
DO $$
DECLARE
  batch_size INT := 5000;
  affected   INT;
BEGIN
  LOOP
    UPDATE users
    SET email_address = email
    WHERE id IN (
      SELECT id FROM users
      WHERE email_address IS NULL AND email IS NOT NULL
      ORDER BY id
      LIMIT batch_size
      FOR UPDATE SKIP LOCKED
    );

    GET DIAGNOSTICS affected = ROW_COUNT;
    EXIT WHEN affected = 0;

    COMMIT;
    PERFORM pg_sleep(0.1);   -- let replicas catch up
  END LOOP;
END $$;

FOR UPDATE SKIP LOCKED يمنع عملية الردم من حظر الصفوف التي يقوم تطبيقك بتحديثها حاليًا. إن فترة النوم القصيرة بين الدفعات هي ما يمنع تزايد تأخر النسخ، وهي الخطوة التي يغفلها الناس ويندمون عليها.

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

تعيين مهلة القفل

يمنع هذا الإعداد الفردي معظم حالات انقطاع الترحيل. وبدون ذلك، فإن عملية الترحيل التي لا يمكنها الحصول على قفل تنتظر إلى أجل غير مسمى – وكل استعلام يتم وضعه في قائمة الانتظار خلفه ينتظر أيضًا، وهذه هي الطريقةALTER TABLE الأكشاك التطبيق بأكمله.

-- Fail fast instead of queueing behind a long-running query.
SET lock_timeout = '3s';
SET statement_timeout = '30s';

ALTER TABLE users ADD COLUMN email_address TEXT;

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

الهجرة بين قواعد البيانات

يستخدم الانتقال إلى محرك قاعدة بيانات جديد أو مثيل جديد نفس المبدأ على نطاق أوسع.

  1. تكرار — إعداد النسخ المتماثل المنطقي أو تغيير التقاط البيانات من القديم إلى الجديد. دعها تلحق بالكامل.
  2. قراءة مزدوجة – القراءة من قاعدة البيانات القديمة، والقراءة من قاعدة البيانات الجديدة في الخلفية لمقارنة النتائج. سجل كل عدم تطابق وقم بإصلاح الأسباب قبل المتابعة.
  3. الكتابة المزدوجة – اكتب لكليهما. القديم لا يزال موثوقا.
  4. قطع – تبديل القراءات إلى قاعدة البيانات الجديدة. استمر في الكتابة لكليهما.
  5. الخروج من الخدمة— توقف عن الكتابة إلى قاعدة البيانات القديمة بمجرد أن تصبح واثقًا من ذلك، مع الاحتفاظ بها كمسار تراجع لفترة ذات معنى.

مرحلة المقارنة في الخطوة 2 هي ما يجعل هذا الأمر آمنًا. ويعني تخطيها اكتشاف اختلافات في البيانات بعد الاستبدال، عندما يكون التراجع مكلفًا.

التخطيط للتراجع

تحتاج كل هجرة إلى إجابة لسؤال “ماذا لو كان هذا خطأ؟” قبل تشغيله.

يتم التراجع عن التغييرات الإضافية بشكل تافه – يعد إسقاط العمود الذي أضفته للتو أمرًا آمنًا لأنه لا شيء يعتمد عليه.

التغييرات المدمرة لا تتراجع. بمجرد إسقاط عمود، تختفي البيانات. وهذا هو بالضبط السبب وراء أن خطوات العقد تأتي أخيرًا وبعد فترة من الثقة.

تحتاج عمليات الردم إلى إمكانية الرجوع أيضًا. إذا قمت بالكتابة فوق عمود، فاحتفظ بالقيم الأصلية في مكان ما حتى تتأكد.

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

قائمة التحقق قبل الرحلة

  • اختبار على نسخة مستعادة من بيانات الإنتاج، على نطاق الإنتاج
  • معرفة ما إذا كانت كل عبارة تأخذ قفل حظر
  • تعيينlock_timeout وstatement_timeout
  • قم بتجميع كل عملية ردم وتشغيلها خارج النشر
  • تأكد من أن كود التطبيق القديم والجديد يعملان مع المخطط الوسيط
  • مشاهدة تأخر النسخ المتماثل أثناء وبعد
  • احصل على نسخة احتياطية تم التحقق منها، واعرف المدة التي تستغرقها عملية الاستعادة
  • النشر أثناء حركة المرور المنخفضة حتى عندما لا تتوقع عدم وجود قفل

الخلاصة

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

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা