لماذا لا يمكن معالجة نشر قواعد البيانات مثل نشر التطبيقات

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

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

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

كيف تعمل الأقفال (Locks) ولماذا تضر

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

بعض تغييرات المخطط سريعة. على سبيل المثال، إضافة عمود بقيمة افتراضية NULL في PostgreSQL يمكن أن يكتمل في ميلي ثانية دون حظر القراءات. لكن العمليات الأخرى ليست بهذه الودية. إنشاء فهرس (index) على جدول كبير، تغيير نوع بيانات عمود، أو حذف عمود يمكن أن يقفل الجدول لدقائق أو حتى ساعات.

تأمل الفرق بين هاتين العبارتين SQL:

-- آمن: يضيف عمودًا قابلًا للقيمة NULL، يكتمل في ميلي ثانية، لا قفل
ALTER TABLE products ADD COLUMN discount_price DECIMAL(10,2);

-- خطير: يعيد كتابة الجدول بأكمله، يقفل لدقائق على الجداول الكبيرة
ALTER TABLE products ALTER COLUMN price TYPE DECIMAL(12,2);

العبارة الأولى تضيف عمودًا يمكن أن يكون NULL، لذا تقوم قاعدة البيانات فقط بتحديث البيانات الوصفية (metadata). العبارة الثانية تغير نوع بيانات عمود موجود، مما يجبر قاعدة البيانات على إعادة كتابة كل صف في الجدول. أثناء تشغيل إعادة الكتابة، يكون الجدول مقفلاً، ويجب أن تنتظر جميع الاستعلامات ضد products.

الخطر الحقيقي هو التأثير المتتالي (cascade effect). استعلام ينتظر قفلًا لا يبطئ ميزة واحدة فقط. يمكنه حظر استعلامات أخرى تعتمد على نفس الجدول. في الحالات القصوى، يتوقف التطبيق عن الاستجابة تمامًا لأن جميع خيوط قاعدة البيانات (threads) تُستهلك بواسطة استعلامات تنتظر الأقفال. يرى المستخدمون مؤشرات تحميل لا نهائية أو أخطاء انتهاء المهلة (timeout). من منظور المستخدم، التطبيق معطل. قاعدة البيانات مشغولة فقط بحماية نفسها.

ليست كل تغييرات المخطط متساوية

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

يمكن لـ PostgreSQL إضافة عمود بقيمة افتراضية NULL دون حظر القراءات. عمليات ONLINE DDL في MySQL يمكن أن تعمل دون قفل الجدول لعمليات DML المتزامنة، لكنها لا تزال تتطلب قفل بيانات وصفية (metadata lock) لفترة وجيزة في البداية والنهاية. حتى العمليات التي تدّعي أنها "عبر الإنترنت" أو "بدون توقف" تحتاج إلى اختبار في بيئة تحاكي الإنتاج.

العمليات التي تسبب عادةً معظم المشاكل:

  • إنشاء فهارس على جداول كبيرة
  • تغيير أنواع بيانات الأعمدة
  • حذف الأعمدة
  • إضافة أعمدة بقيم افتراضية غير NULL (في بعض قواعد البيانات)
  • إعادة تسمية الأعمدة أو الجداول
  • تشغيل عبارات ALTER TABLE التي تعيد كتابة الجدول بأكمله

العمليات الآمنة عمومًا:

  • إضافة أعمدة بقيمة افتراضية NULL (في PostgreSQL)
  • إضافة فهارس باستخدام CONCURRENTLY (في PostgreSQL)
  • إنشاء جداول جديدة
  • إضافة أعمدة جديدة باستخدام ONLINE DDL (في MySQL، للعمليات المدعومة)

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

لماذا الاسترجاع (Rollback) أصعب مما تعتقد

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

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

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

استراتيجيات عملية لنشر قواعد بيانات أكثر أمانًا

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

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

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

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

مراقبة أوقات انتظار القفل أثناء الترحيل. قم بإعداد تنبيهات تُطلق عندما تبدأ الاستعلامات في انتظار الأقفال لأكثر من بضع ثوانٍ. إذا رأيت أوقات انتظار القفل ترتفع، فأنت بحاجة إلى إجراء لإحباط الترحيل قبل أن يتسبب في انقطاع كامل.

امتلاك إجراء إحباط واضح. حدد بالضبط ما يجب فعله إذا كان الترحيل يستغرق وقتًا طويلاً أو يسبب تنافسًا على الأقفال (lock contention). قد يعني هذا قتل عملية الترحيل، أو الاسترجاع إلى إصدار المخطط السابق، أو التبديل إلى نسخة متماثلة للقراءة (read replica) أثناء اكتمال الترحيل.

قائمة مراجعة عملية لنشر قواعد البيانات

قبل تشغيل أي تغيير مخطط في الإنتاج، اتبع قائمة المراجعة هذه:

  • هل هذه العملية آمنة للقراءة والكتابة المتزامنة في نظام قاعدة البيانات الخاص بك؟
  • هل اختبرت الترحيل في بيئة اختبار بحجم بيانات مماثل؟
  • ما هو وقت التنفيذ المقدر بناءً على اختبارات بيئة الاختبار؟
  • هل الترحيل مجدول خلال نافذة حركة مرور منخفضة؟
  • هل لديك خطة استرجاع لا تتطلب ترحيلًا خطيرًا آخر؟
  • هل تم تكوين تنبيهات المراقبة لأوقات انتظار القفل؟
  • هل يعرف الفريق إجراء الإحباط إذا حدث خطأ ما؟

الفرق الجوهري

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

الفرق التي تنجح في نشر قواعد البيانات هي تلك التي تحترم هذا الاختلاف. إنها لا تكتفي بإضافة خطوات الترحيل إلى نفس خط الأنابيب (pipeline) الذي ينشر كود التطبيق. إنها تصمم سير عمل منفصلة مع ضمانات مناسبة، وإجراءات اختبار، ومراقبة.

في المرة القادمة التي تخطط فيها لتغيير قاعدة بيانات، ابدأ بالسؤال: "ماذا يحدث للمستخدمين أثناء تشغيل هذا الترحيل؟" الإجابة على هذا السؤال ستخبرك ما إذا كنت مستعدًا للنشر.