Database Engineering

سد الفجوة: تنفيذ تغييرات المخطط دون توقف في عناقيد PostgreSQL المقسمة

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

يستكشف هذا المقال أنماط البنية والاستراتيجيات التشغيلية المطلوبة لتنفيذ تغييرات المخطط عبر الإنترنت في بيئات PostgreSQL المقسمة. سننتقل إلى ما وراء قيود آليات القفل التقليدية، ونغوص في كيفية استخدام النسخ المنطقي، وأنماط الكتابة المزدوجة، والهجرة التدريجية للحفاظ على تشغيل خدماتك بنسبة 100% من الوقت.

قيود التقسيم

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

في الإعداد المقسم، يقوم التطبيق بتوجيه الاستعلامات إلى شرائح محددة بناءً على مفتاح التقسيم (مثل user_id). إذا تم إجراء تغيير في المخطط على شريحة واحدة ولكن ليس على الأخرى، أو إذا تم إجراء التغيير بطريقة تسبب قفلًا طويلاً، فقد يواجه التطبيق فشلًا جزئيًا، أو رؤية بيانات غير متسقة، أو توقفًا كليًا للخدمة خلال النافذة الزمنية. لذلك، يجب أن تكون استراتيجية الهجرة قابلة للتنفيذ بشكل متكرر (idempotent)، وآمنة، وقابلة للتنفيذ دون الاحتفاظ بقفل يعطل حركة المرور القياسية للقراءة والكتابة.

استراتيجية الكتابة المزدوجة

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

المرحلة 1: ملء العمود الجديد

أولاً، أدخل العمود الجديد إلى المخطط على جميع الشرائح. استخدام ADD COLUMN بدون قيمة افتراضية سريع للغاية لأن PostgreSQL يقوم فقط بتحديث رأس السجل (tuple header) وليس البيانات الموجودة.

-- نفذ على جميع الشرائح
ALTER TABLE events ADD COLUMN new_tracking_id UUID;

في هذه المرحلة، يستمر التطبيق في العمل بشكل طبيعي. تتعايش البيانات القديمة والجديدة. ومع ذلك، فإن العمود الجديد فارغ (NULL) حاليًا لجميع السجلات التاريخية.

المرحلة 2: الملء والكتابة المزدوجة

بعد ذلك، شغل مهمة خلفية لتعبئة العمود الجديد بالبيانات التاريخية. يجب تقييد هذه العملية لتجنب إغراق نظام الإدخال/الإخراج. في الوقت نفسه، قم بتحديث كود التطبيق لكتابة البيانات في كل من العمود القديم والعمود الجديد (الكتابة المزدوجة).

-- كود التطبيق الوهمي
INSERT INTO events (event_type, old_tracking_id, new_tracking_id)
VALUES ('purchase', 12345, gen_random_uuid());

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

النسخ المنطقي للتنسيق

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

هذا النهج مفيد بشكل خاص عندما تحتاج إلى تغيير أنواع البيانات أو إعادة هيكلة الجداول بشكل كبير. تتضمن العملية:

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

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

إطلاق التغيير

بمجرد اكتمال مرحلة الكتابة المزدوجة وانتهاء عملية الملء، تكون جاهزًا للقطع النهائي. غالبًا ما تكون هذه المرحلة هي الأسرع، حيث تكون البيانات موجودة بالفعل.

  1. التحويل للقراءة فقط: قم بتحديث التطبيق لقراءة البيانات حصريًا من العمود الجديد أو من بنية الجدول الجديد.
  2. حذف العمود القديم: بمجرد التأكد من عدم قراءة أي بيانات من البنية القديمة، احذف العمود القديم.
  3. إضافة القيود: أخيرًا، فرض قيود NOT NULL أو فهارس فريدة على العمود الجديد لضمان سلامة البيانات.
-- المرحلة 3: التنظيف
ALTER TABLE events DROP COLUMN old_tracking_id;
ALTER TABLE events ALTER COLUMN new_tracking_id SET NOT NULL;

الخلاصة

تنفيذ تغييرات المخطط في عناقيد PostgreSQL المقسمة يتطلب الابتعاد عن عقلية "القفل والحذف". من خلال الاستفادة من أنماط الكتابة المزدوجة، والملء الخلفي في الخلفية، والنسخ المنطقي، يمكن للمهندسين تحقيق هجرات حقيقية دون توقف. بينما تقدم هذه الاستراتيجيات تعقيدًا أوليًا في كود التطبيق وأدوات التشغيل، فإن العائد هو بنية تحتية لقاعدة البيانات تتوسع مع عملك دون التضحية بالتوفر.

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

Share: