لماذا استرجاع قاعدة البيانات أصعب من استرجاع التطبيق
تنشر نسخة جديدة من تطبيقك. يحدث خطأ ما. تضغط على زر الاسترجاع، فتعود النسخة القديمة للعمل، وفي غضون دقائق يعود كل شيء إلى طبيعته. لا بيانات مفقودة، ولا آثار جانبية باقية. العملية تبدو نظيفة وقابلة للعكس.
تخيل الآن سيناريو مختلفًا. تقوم بتنفيذ ترحيل قاعدة بيانات يضيف عمود status إلى جدول orders. يكتمل الترحيل، ويتم ملء العمود الجديد بقيم افتراضية، ويبدأ تطبيقك المحدث في كتابة بيانات حقيقية في ذلك العمود. بعد بضع ساعات، تكتشف خطأ في منطق التطبيق يجعل قيم status غير موثوقة. تقرر استرجاع التطبيق إلى الإصدار السابق. الكود القديم يعمل الآن مرة أخرى. لكن عمود status لا يزال موجودًا. والبيانات التي كُتبت فيه لا تزال موجودة. وقد لا يعرف كود تطبيقك القديم كيفية التعامل مع هذا العمود الإضافي، أو الأسوأ من ذلك، قد يتعطل لأنه يواجه عمودًا لم يتوقعه أبدًا.
هذه هي المشكلة الأساسية: استرجاع التطبيق يعيد الكود فقط. استرجاع قاعدة البيانات يجب أن يعيد كلاً من الهيكل والبيانات إلى حالتها قبل الترحيل. وهذا لا يحدث تلقائيًا.
لماذا استرجاع التطبيق بسيط
عندما تسترجع تطبيقًا، فأنت ببساطة تستبدل مجموعة من الكود القابل للتنفيذ بأخرى. تتولى النسخة القديمة المهمة، وتبدأ في معالجة الطلبات الجديدة، ويستمر النظام. لا يتم تعديل أي حالة دائمة أثناء عملية الاسترجاع نفسها. تبقى قاعدة البيانات كما كانت تمامًا قبل تشغيل الاسترجاع. الشيء الوحيد الذي يتغير هو إصدار الكود الذي يعمل.
هذه البساطة هي السبب في أن العديد من الفرق تتعامل مع الاسترجاع كشبكة أمان. إذا حدث خطأ ما، فقط قم بالعودة وحاول مرة أخرى لاحقًا. يعمل هذا بشكل جيد للخدمات عديمة الحالة وللتطبيقات التي لا يتغير فيها مخطط قاعدة البيانات بين الإصدارات.
لماذا يختلف استرجاع قاعدة البيانات
يتضمن استرجاع قاعدة البيانات التراجع عن تغييرات هيكلية في مخزن بيانات مباشر. وهذا يعني إزالة الأعمدة، أو استعادة الجداول المحذوفة، أو إعادة القيود التي تم تغييرها. وعلى عكس كود التطبيق، تحتوي قواعد البيانات على بيانات ربما تم تعديلها أو إضافتها أو حذفها منذ تشغيل الترحيل.
ضع في اعتبارك ترحيلاً يزيل عمودًا باسم legacy_flag من جدول users. إذا كنت بحاجة إلى الاسترجاع، يجب عليك إضافة هذا العمود مرة أخرى. لكن ماذا عن البيانات التي كانت في ذلك العمود؟ إذا كان الترحيل قد أسقطه ببساطة، فإن تلك البيانات قد اختفت ما لم تكن قد قمت بنسخها احتياطيًا مسبقًا. إذا كان الترحيل قد أعاد تسمية العمود أو تحويله، فأنت بحاجة إلى عكس هذا التحويل تمامًا، دون إفساد أي بيانات جديدة ربما تكون قد كُتبت في هذه الأثناء.
إليك مثال ملموس يوضح المشكلة. يضيف ترحيل أمامي عمودًا، ويحاول الاسترجاع المقابل إزالته:
-- الترحيل الأمامي: إضافة عمود NOT NULL بقيمة افتراضية
ALTER TABLE orders ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'pending';
-- بعد ساعات، يكتب كود التطبيق الجديد قيم حالة حقيقية
-- بعض الصفوف الآن لديها status = 'shipped', 'cancelled', إلخ.
-- ترحيل الاسترجاع: إزالة العمود
ALTER TABLE orders DROP COLUMN status;
-- ينجح هذا، لكن جميع بيانات الحالة تُفقد بشكل دائم.
إذا حاول ترحيل الاسترجاع بدلاً من ذلك الاحتفاظ بالبيانات عن طريق إعادة تسمية العمود أو تحويله، فسيحتاج إلى التعامل مع القيود والفهارس وأي بيانات جديدة كتبها التطبيق القديم بعد الاسترجاع — وهي عملية هشة وغالبًا ما تكون غير مختبرة.
هذه ليست مشكلة نظرية. الفرق التي تعتمد على هجرات الاسترجاع (down migrations) — وهي نصوص برمجية تعكس التغييرات التي أجراها الترحيل الأمامي — غالبًا ما تكتشف أن هذه النصوص نادرًا ما تُختبر، وأحيانًا تكون معطلة، ودائمًا ما تكون محفوفة بالمخاطر عند تشغيلها في الإنتاج. هجرة استرجاع تفشل في منتصف الطريق يمكن أن تترك قاعدة البيانات في حالة غير متناسقة، مع تراجع بعض التغييرات والبعض الآخر لا.
النهج الأكثر أمانًا: الهجرات المتوافقة مع الإصدارات السابقة
الإستراتيجية الأكثر موثوقية هي تصميم كل ترحيل لقاعدة البيانات ليكون متوافقًا مع الإصدارات السابقة. هذا يعني أن تغييرات المخطط التي تجريها يجب ألا تعطل الإصدار القديم من تطبيقك. إذا كنت بحاجة إلى إضافة عمود جديد، قم بإضافته دون إزالة أو تعديل الأعمدة الموجودة. يستمر التطبيق القديم في العمل لأنه ببساطة يتجاهل العمود الجديد. يبدأ التطبيق الجديد في استخدامه. إذا تبين أن الإصدار الجديد به خلل، يمكنك استرجاع التطبيق دون لمس قاعدة البيانات على الإطلاق. يبقى العمود الإضافي، لكن الكود القديم لا يهتم به.
يتطلب هذا النهج انضباطًا. يجب تقييم كل تغيير في المخطط من حيث تأثيره على جميع إصدارات التطبيق التي قد لا تزال قيد التشغيل. لكنه أكثر أمانًا بكثير من الاعتماد على هجرات الاسترجاع التي يمكن أن تفشل أو تفقد البيانات.
إليك كيفية عمل الهجرات المتوافقة مع الإصدارات السابقة في الممارسة العملية للعمليات الشائعة:
إضافة عمود: فقط قم بإضافته. لا تجعله
NOT NULLإلا إذا كان بإمكانك توفير قيمة افتراضية تعمل لكل من الكود القديم والجديد. لن يقرأه التطبيق القديم أو يكتب فيه، لذا لن يتأثر.إعادة تسمية عمود: لا تقم بإعادة تسميته مباشرة. بدلاً من ذلك، أضف العمود الجديد بالاسم الجديد، وقم بتحديث التطبيق للكتابة في كلا العمودين خلال فترة انتقالية، ثم قم بإزالة العمود القديم في ترحيل لاحق بعد التأكد من أن الكود القديم لم يعد قيد التشغيل.
إزالة عمود: توقف عن استخدامه في التطبيق أولاً. انشر هذا التغيير. ثم، في ترحيل منفصل، قم بإسقاط العمود. إذا كنت بحاجة إلى استرجاع التطبيق، فإن العمود لا يزال موجودًا.
تغيير نوع عمود: أضف عمودًا جديدًا بالنوع الجديد، وقم بترحيل البيانات تدريجيًا، وقم بتحديث التطبيق لاستخدام العمود الجديد، وعندها فقط قم بإزالة العمود القديم.
كل من هذه الأنماط يضيف خطوات، لكن كل خطوة قابلة للعكس دون فقدان البيانات.
التكلفة الحقيقية لهجرات الاسترجاع
لا يزال بعض الفرق يفضلون هجرات الاسترجاع لأنها تبدو أبسط في الكتابة. نص برمجي واحد يعكس التغيير يبدو أنظف من نهج متعدد الخطوات متوافق مع الإصدارات السابقة. لكن تكلفة تلك البساطة تظهر تحت الضغط.
عندما يحدث حادث إنتاج وتحتاج إلى الاسترجاع بسرعة، فإن آخر شيء تريده هو تشغيل هجرة استرجاع غير مختبرة قد تفشل، أو تستغرق وقتًا طويلاً، أو تسقط البيانات بصمت. ضغط الوقت، والتوتر، وعدم وجود خطة احتياطية نظيفة يجعل من هجرات الاسترجاع مقامرة.
الهجرات المتوافقة مع الإصدارات السابقة تزيل هذه المقامرة. إنها تتيح لك استرجاع التطبيق بشكل مستقل عن قاعدة البيانات. إنها تمنحك الوقت لتقرر ما يجب فعله بشأن تغيير المخطط دون إجبارك على تراجع فوري ومحفوف بالمخاطر.
قائمة مراجعة عملية لتخطيط استرجاع قاعدة البيانات
إذا كنت تريد تجنب سيناريوهات الاسترجاع المؤلمة، إليك قائمة مراجعة قصيرة لمراجعتها قبل كل ترحيل:
- هل يمكن لإصدار التطبيق القديم الاستمرار في العمل بشكل صحيح بعد هذا الترحيل؟
- إذا كان الترحيل يضيف عمودًا، هل يتجاهله الكود القديم؟
- إذا كان الترحيل يزيل عمودًا، هل توقف الكود القديم بالفعل عن استخدامه؟
- إذا كان الترحيل يعيد تسمية أو يغير عمودًا، هل هناك فترة انتقالية يتعايش فيها الهيكلان القديم والجديد؟
- هل هناك طريقة آمنة ومختبرة لعكس هذا الترحيل دون فقدان البيانات؟
إذا لم تستطع الإجابة بنعم على كل هذه الأسئلة، فإن الترحيل الخاص بك يحمل مخاطر استرجاع لم تعالجها.
الخلاصة
استرجاع قاعدة البيانات لا يتعلق فقط بإعادة إصدار. إنه يتعلق بالحفاظ على البيانات سليمة ومتسقة مع ضمان أن التطبيق يمكنه العودة إلى حالته السابقة دون آثار جانبية. المسار الأكثر أمانًا هو تصميم هجرات لا تجبرك على الاختيار بين استرجاع التطبيق وفقدان البيانات. قم ببناء التوافق مع الإصدارات السابقة في كل تغيير مخطط، وتعامل مع هجرات الاسترجاع كخيار أخير، وليس كاستراتيجية افتراضية. مستقبلك، وأنت تتصيد الأخطاء في حادثة الساعة 2 صباحًا، سيشكرك.