11 ديسمبر 2025·6 دقيقة قراءة

تغييرات المخطط بدون توقف: هجرات إضافية آمنة

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

تغييرات المخطط بدون توقف: هجرات إضافية آمنة

ماذا يعني "عدم التوقف" فعليًا لتغييرات المخطط

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

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

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

تطبيقات الموبايل القديمة والعملاء المخزنين مؤقتًا مشكلة متكررة لأنك لا تستطيع تحديثهم فورًا. بعض المستخدمين يحتفظون بإصدار التطبيق أسابيع. آخرون لديهم اتصال متقطع ويعيدون المحاولات لاحقًا. حتى عملاء الويب يمكن أن يتصرفوا كإصدارات قديمة عندما يحتفظ عامل الخدمة (service worker) أو CDN أو بروكسي بكود أو افتراضات قديمة.

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

تعريف عملي: يجب أن تكون قادرًا على نشر الشيفرة والمخطط بأي ترتيب، ويظل النظام يعمل.

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

ابدأ بتغييرات إضافية لا تكسر الشيفرة الحالية

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

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

عند إضافة أعمدة، ابدأ بالحقول القابلة لأن تكون فارغة (nullable). عمود قابل لأن يكون فارغ يسمح للكود القديم بمواصلة إدراج الصفوف دون المعرفة بالحقل الجديد. إذا كنت تريد في النهاية NOT NULL، أضف الحقل كقابل لأن يكون فارغ أولًا، عبّئ البيانات، ثم فَرِّض NOT NULL لاحقًا. القيم الافتراضية يمكن أن تساعد أيضًا، لكن احذر: إضافة قيمة افتراضية قد تلمس العديد من الصفوف في بعض قواعد البيانات، مما قد يبطئ التغيير.

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

مجموعة قواعد بسيطة لهجرات قواعد البيانات الإضافية:

  • أضف جداول أو أعمدة جديدة أولًا، واترك القديمة دون مساس.
  • اجعل الحقول الجديدة اختيارية (nullable) حتى تُملأ البيانات.
  • حافظ على عمل الاستعلامات والحمولات القديمة حتى يتم تحديث العملاء.
  • أجّل القيود (NOT NULL، unique، المفاتيح الخارجية) حتى بعد التعبئات.

خطة طرح خطوة بخطوة تحافظ على عمل العملاء القدامى

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

تسلسل عملي:

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

مثال: تُدخل الحقل full_name بينما العملاء القدامى ما زالوا يرسلون first_name وlast_name. لفترة، يمكن للخادم أن يُنشئ full_name عند الكتابة، ويعبّئ المستخدمين الموجودين، ثم يقرأ full_name افتراضيًا بينما لا يزال يدعم الحمولة القديمة. فقط بعد وضوح الاعتماد تحذف الحقول القديمة.

تعبئات بلا مفاجآت: كيف تملأ البيانات الجديدة بأمان

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

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

قَسِّم العمل لدفعات حتى تتحكَّم في ضغط قاعدة البيانات. لا تُحدّث ملايين الصفوف في معاملة واحدة. استهدف حجم دفعة متوقع وفترة توقف قصيرة بين الدفعات حتى يبقى برافُّ المستخدمين سلسًا.

نمط عملي:

  • اختر دفعة صغيرة (مثال: الألف صف التالية) باستخدام مفتاح مفهرس.
  • حدّث ما ينقص فقط (تجنّب إعادة كتابة الصفوف المعبّأة بالفعل).
  • اكتب بسرعة، ثم نم مؤقتًا.
  • سجّل التقدّم (آخر معرف معالج أو طابع زمني).
  • أعد المحاولة عند الفشل دون البدء من الصفر.

اجعل المهمة قابلة لإعادة التشغيل. خزّن علامة تقدّم بسيطة في جدول مخصص، وصمّم المهمة بحيث لا تُفسد البيانات عند التشغيل المتكرر. التحديثات الهوية (مثال: تحديث حيث new_field IS NULL) صديقة لهذه الحالة.

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

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

قواعد توافق API لإصدارات العملاء المختلطة

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

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

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

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

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

قواعد توافق تمنع معظم الانقطاعات:

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

مثال: تضيف company_size إلى تدفق التسجيل. يمكن للباكند وضع افتراضي مثل "unknown" عند غياب الحقل. العملاء الجدد يرسلون القيمة الحقيقية، والعملاء القدامى يواصلون العمل، ولوحات التحكم تظل قابلة للقراءة.

عندما يُعاد توليد التطبيق: الحفاظ على اتساق المخطط والمنطق

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

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

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

ماذا تعيد الاختبار بعد كل إعادة توليد

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

  • التسجيل، تسجيل الدخول، إعادة تعيين كلمة المرور، تجديد الرموز.
  • عمليات الإنشاء والتحديث الأساسية (الأكثر استخدامًا).
  • فحوصات الصلاحيات والإدارة.
  • المدفوعات وwebhooks (مثل أحداث Stripe).
  • الإشعارات والمراسلة (البريد/الرسائل، Telegram).

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

أخطاء شائعة تسبب الانقطاع (وكيف تتجنبها)

حافظ على اتساق المخطط والشيفرة
أعد توليد شيفرة مصدر نظيفة مع تطور المخطط، دون الاحتفاظ بباتشات فوضوية.
توليد الشيفرة

معظم الانقطاعات أثناء تغييرات المخطط بدون توقف لا تسببها أعمال قاعدة البيانات "الصعبة". تأتي من تغيير العقد بين قاعدة البيانات، الـ API، والعملاء بالترتيب الخطأ.

الفخاخ الشائعة وحركات أكثر أمانًا:

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

إذا أعِدت توليد التطبيق، قد تميل إلى "تنظيف" الأسماء والقيود دفعة واحدة. قاوم هذا الإغراء. التنظيف خطوة أخيرة، وليس الأولى.

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

المراقبة وتخطيط التراجع للطرحات المرحلية

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

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

راقب إشارات تعكس تأثير المستخدم الحقيقي، لا فقط "انتهى النشر":

  • معدل أخطاء الـ API (خاصة قفزات 4xx/5xx على نقاط النهاية المحدثة).
  • الاستعلامات البطيئة (p95 أو p99 لأوقات استعلام الجداول التي لمستها).
  • زمن الكتابة (مدة الإدخالات والتحديثات خلال ذروة الحركة).
  • عمق الطوابير (تكدّس المهام للتعبئات أو معالجة الأحداث).
  • ضغط CPU/IO لقاعدة البيانات (أي قفزة مفاجئة بعد التغيير).

إذا كنت تفعل كتابة مزدوجة (dual writes)، أضف تسجيلًا مؤقتًا يقارن بين الاثنين. اجعله مقتصرًا: سجّل فقط عند اختلاف القيم، تضمّن معرف السجل ورمز سبب قصير، وخذ عينات إذا كان الحجم كبيرًا. أنشئ تذكيرًا لإزالة هذا التسجيل بعد الهجرة حتى لا يصبح ضوضاء دائمة.

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

دليل عملي للرجوع:

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

للتعبئات، اصنع مفتاح إيقاف يمكن قلبه في ثوانٍ (feature flag، قيمة تكوين، إيقاف المهمة). وتواصل المراحل مقدمًا: متى تبدأ الكتابات المزدوجة، متى تعمل التعبئات، متى تُغيّر القراءة، وماذا يعني "توقف" حتى لا يبتكر أحد حلولًا ارتجالية تحت الضغط.

قائمة فحص سريعة قبل النشر

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

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

إذا كنت تستخدم منصة تعيد التوليد، أضف فحصًا آخر: ولّد ونشِر بناءً من النموذج الدقيق الذي تهاجر إليه، ثم تأكد أن الـ API والمنطق المولَّد ما زالا يتسامحان مع السجلات القديمة. فشل شائع هو افتراض أن المخطط الجديد يعني منطقًا مطلوبًا جديدًا.

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

مثال: إضافة حقل جديد بينما تطبيقات الموبايل القديمة لا تزال نشطة

ابنِ تطبيقات قابلة للتغيير
استخدم AppMaster لبناء تطبيقات ويب وموبايل بمنطق باكند يمكن أن يتطور بأمان.
ابدأ مشروعًا

لديك تطبيق طلبات. تحتاج حقلًا جديدًا، delivery_window، وسيصبح مطلوبًا لقواعد عمل جديدة. المشكلة أن إصدارات iOS وAndroid القديمة لا تزال مستخدمة ولن ترسل هذا الحقل لأيام أو أسابيع. إذا جعلت قاعدة البيانات تطلبه فورًا، سيبدأ هؤلاء العملاء بالفشل.

مسار آمن:

  • المرحلة 1: أضف العمود كقابل لأن يكون فارغ، بدون قيود. حافظ على القراءة والكتابة الحالية.
  • المرحلة 2: كتابة مزدوجة. العملاء الجدد (أو الباكند) يكتبون الحقل الجديد. العملاء القدامى يواصلون العمل لأن العمود يقبل القيم الفارغة.
  • المرحلة 3: تعبئة. عبّئ delivery_window للصفوف القديمة باستخدام قاعدة (استنتاج من طريقة الشحن، أو افتراضيًا "أي وقت" حتى يعدله العميل).
  • المرحلة 4: تغيير القراءة. حدّث الـ API والواجهة لقراءة delivery_window أولًا، لكن ارجع إلى القيمة المستنتجة عندما تكون فارغة.
  • المرحلة 5: فرض لاحقًا. بعد الاكتساب وإتمام التعبئة، أضف NOT NULL وأزل الحل الاحتياطي.

ما يشعر به المستخدمون في كل مرحلة يظل مملًّا (وهذا الهدف):

  • مستخدمو الموبايل القدامى ما زالوا يقدّمون طلبات لأن الـ API لا يرفض غياب البيانات.
  • المستخدمون الجدد يرون الحقل الجديد وتُحفظ اختياراتهم بصورة متسقة.
  • الدعم والعمليات يرون الحقل يمتلئ تدريجيًا دون فجوات مفاجئة.

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

الخطوات التالية: صنع دفتر هجرات قابل للتكرار

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

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

قالب بسيط:

  • أضف فقط (عمود/جدول/فهرس جديد، حقل API جديد اختياري).
  • انشر شيفرة يمكنها قراءة الشكلين القديم والجديد.
  • عبّئ على دفعات صغيرة، مع إشارة "تم" واضحة.
  • قلب السلوك بعلم ميزة أو إعداد، وليس بإعادة نشر.
  • أزل الحقول/النهايات القديمة بعد تاريخ قطع وفحص.

ابدأ بطاولة منخفضة المخاطر (حالة اختيارية جديدة، حقل ملاحظات) ونفّذ دفتر اللعب كاملاً: تغيير إضافي، تعبئة، عملاء متعددو الإصدارات، ثم تنظيف. تجربة تدريبية تكشف ثغرات المراقبة، التجزئة، والتواصل قبل محاولة إعادة تصميم كبيرة.

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

إذا بنيت مع AppMaster، يمكنك اعتبار إعادة التوليد كجزء من عملية الأمان: نمذج المخطط الإضافي، حدّث منطق الأعمال ليتعامل مع الحقول القديمة والجديدة خلال الانتقال، وأعد التوليد حتى تبقى الشيفرة المصدرية نظيفة مع تغير المتطلبات. إذا أردت رؤية كيف يتناسب هذا الأسلوب مع إعداد بدون كود ينتج شيفرة فعلية، فـ AppMaster (appmaster.io) مصممة حول نمط التسليم المرحلي هذا.

الهدف ليس الكمال. الهدف هو التكرارية: كل هجرة لها خطة، قياس، ومخرج طوارئ.

الأسئلة الشائعة

ماذا يعني "عدم التوقف" فعليًا لتغيير المخطط؟

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

لماذا تكسر تغييرات المخطط الأشياء حتى لو نجحت الهجرة؟

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

لماذا تعد تطبيقات الموبايل القديمة مخاطرة كبيرة أثناء الهجرات؟

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

ما نوع تغيير المخطط الأكثر أمانًا للقيام به بدون توقف؟

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

كيف أضيف حقلًا مطلوبًا بدون كسر العملاء القدامى؟

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

ما تسلسل الطرح العملي لهجرة بدون توقف؟

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

كيف أعبئ البيانات بدون التسبب في قفلات أو تباطؤ؟

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

كيف أحافظ على توافق API بينما يتغير المخطط؟

اجعل الحقول الجديدة اختيارية في البداية وطبّق قيم افتراضية على الخادم عند غيابها. حافظ على السلوك القديم ثابتا، تجنّب تغيير معنى الحقول الحالية، واختبر المسارين: «العميل الجديد يرسل الحقل» و«العميل القديم يحذفه».

ما أفضل خطة للتراجع أثناء هجرة مرحلية؟

في معظم الحالات ستعيد نقطة الرجوع (rollback) شيفرة التطبيق وليس المخطط. احتفظ بالأعمدة/الجداول الإضافية، أوقف القراءات الجديدة أولًا ثم أوقف الكتابات الجديدة، وأوقف التعبئات حتى تستقر المقاييس لاستعادة الحالة بسرعة بدون فقد بيانات.

ماذا يجب أن أراقب لأعرف أنه آمن للانتقال إلى المرحلة التالية؟

راقب إشارات تؤثر فعليًا على المستخدم: معدلات الأخطاء (4xx/5xx) على نقاط النهاية المحدثة، استعلامات بطيئة (p95/p99) للجداول المتأثرة، زمن كتابة السجلات، عمق الطوابير، وارتفاع CPU/IO لقاعدة البيانات بعد التغيير.

من السهل أن تبدأ
أنشئ شيئًا رائعًا

تجربة مع AppMaster مع خطة مجانية.
عندما تكون جاهزًا ، يمكنك اختيار الاشتراك المناسب.

البدء