متى تكون ترحيلات قاعدة البيانات العكسية آمنة ومتى تصبح خطيرة

لقد قمت للتو بنشر ترحيل قاعدة بيانات أضاف عمود phone_number إلى جدول users. بعد بضع ساعات، لاحظ أحدهم أن اسم العمود كان يجب أن يكون phone ليتوافق مع باقي قاعدة الكود. رد فعلك الأول هو تشغيل الترحيل العكسي (down migration)، حذف العمود، وإعادة النشر بالاسم الصحيح. بسيط، أليس كذلك؟

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

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

الترحيلات العكسية آمنة في مراحل التطوير المبكرة

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

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

بيئة الاختبار (Staging) تقدم أولى المخاطر الحقيقية

بيئات الاختبار تقع في منطقة رمادية. الترحيلات العكسية لا تزال تعمل هنا، لكنها تبدأ في إظهار حوافها الخطيرة.

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

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

الإنتاج: حيث تصبح الترحيلات العكسية خطيرة

الإنتاج هو المكان الذي ينهار فيه المفهوم البسيط لـ "التراجع". ثلاث مشاكل محددة تجعل الترحيلات العكسية محفوفة بالمخاطر في بيئات الإنتاج.

يوضح مخطط الحالة التالي كيف تتغير سلامة الترحيلات العكسية عبر البيئات:

تأمل هذا الترحيل الذي أضاف عمود phone_number إلى جدول users:

-- Up migration
ALTER TABLE users ADD COLUMN phone_number varchar(20);

-- Down migration
ALTER TABLE users DROP COLUMN phone_number;

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

flowchart TD Dev[Development] -->|No users, no data risk| Staging[Staging] Staging -->|Production-like data, habit formation| Prod[Production] Prod -->|Data loss| DataLoss[Data Loss Is Permanent] Prod -->|Code-schema mismatch| Sync[Code and Schema Out of Sync] Prod -->|Irreversible changes| Irreversible[Some Changes Cannot Be Reversed]

فقدان البيانات دائم

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

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

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

الكود ومخطط قاعدة البيانات يصبحان غير متزامنين

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

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

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

بعض التغييرات لا يمكن عكسها

بعض الترحيلات مدمرة بطبيعتها. تأمل ترحيلًا يجمع first_name و last_name في عمود واحد full_name. البيانات الأصلية تم تحويلها. تشغيل ترحيل عكسي يمكنه إعادة إنشاء العمودين first_name و last_name، لكن البيانات داخلهما لن تطابق ما كان موجودًا قبل الترحيل. الفصل الأصلي فقد.

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

متى تكون الترحيلات العكسية مقبولة في الإنتاج

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

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

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

قائمة تحقق عملية قبل تشغيل ترحيل عكسي في الإنتاج

قبل تشغيل ذلك الترحيل العكسي، اسأل هذه الأسئلة:

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

إذا أجبت بـ "نعم" على أي من الأسئلة الثلاثة الأولى، لا تقم بتشغيل الترحيل العكسي. اكتب ترحيلًا أماميًا بدلاً من ذلك.

البديل الأكثر أمانًا: التحرك للأمام، وليس للخلف

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

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

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