افصل القابس. اضغط على مفتاح الإيقاف الفوري. هذه الغرائز تنجح عندما تقف بجانب آلة واحدة، لكنها تفشل عندما يمتد نظام الذكاء الاصطناعي الخاص بك عبر خمسين عقدة (node) موزعة على ثلاث مناطق توافر (availability zones). تتعلم معظم الفرق الهندسية هذا الدرس بالطريقة الصعبة؛ حيث يقومون بتحديث قاعدة بيانات مركزية، ويغيرون قيمة منطقية (boolean) من true إلى false ويفترضون أن النظام سيتوقف. لكنه لا يتوقف. تبدو قاعدة البيانات نظيفة، بينما لا تزال الخدمة تعمل.

وهم المفتاح الواحد

تخيل متحكمًا يسجل عملية إلغاء صلاحية عند الحقبة (epoch) 12. يقوم بكتابة التغيير في مخزن دائم ويتنفس الصعداء. في هذه الأثناء، يعمل العامل B بناءً على تصريح مخزن مؤقتًا من الحقبة 11. لم يتلقَّ العامل الإشعار أبدًا. وبعد ثلاثين ثانية، يبدأ مهمة استنتاج للنموذج (model inference job)، أو يقوم بتشغيل عنقود GPU، أو يستدعي API خارجيًا. يقول سجل التدقيق إن الوصول قد أُلغي، ومع ذلك تمت العملية على أي حال.

هذه هي الفجوة بين الاستمرارية (persistence) والانتشار (propagation). الكتابة في قاعدة البيانات ليست هي حالة النظام؛ بل هي مجرد صف واحد في جدول واحد، وهناك العديد من الجهات الفاعلة في نظامك لا تستعلم من ذلك الجدول في اللحظة التي تحتاج فيها إلى ذلك بالضبط. إذا عاملت إيقاف الطوارئ كمفتاح ضوء، فستكتشف أن الظلام لا يحل أبدًا في بعض زوايا الغرفة.

الواقع القاسي للأنظمة الموزعة

عليك أن تصمم لمواجهة الفشل. ليس الفشل العرضي، بل الفشل المستمر، والفوضوي، والمستقل. العمال يعيدون التشغيل في منتصف المهمة. مستهلكو الطوابير (queue consumers) يتأخرون لعدة دقائق. خدمات التفويض تعيد بيانات قديمة لأن إحدى النسخ المتماثلة (replicas) عالقة. الرسائل تتكرر. الرسائل تختفي. الرسائل تصل بترتيب خاطئ. برنامج NTP daemon ينحرف، وفجأة تعتقد إحدى العقد أنها متأخرة عن العقد الأخرى بعشر ثوانٍ. الساعات تحتوي على أخطاء، ولا يمكنك الاعتماد على الوقت الفعلي (wall time) لترتيب الأحداث عبر الحدود.

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

خمس قواعد تعمل حقًا

تأتي السلامة من الثوابت (invariants) التي تصمد أمام الفوضى. إليك القواعد التي تمنع تحول إلغاء الصلاحية إلى مجرد وهم.

لا تبدأ أي عملية بحقبة تصريح (grant epoch) أقل من حقبة الإلغاء (revocation epoch).
هذا هو حاجز الحماية الأساسي لديك. كل منح لصلاحية يحمل رقم حقبة، وكل إلغاء يحمل رقمًا أحدث. قبل أن يقوم أي عامل بأي إجراء، يقارن الأرقام. إذا كانت الحقبة التي يحملها العامل أقدم من أحدث إلغاء رآه، يتوقف العامل. تمنحك الحقبات (epochs) ساعة منطقية لا تعتمد على ساعة النظام. يجب على العامل الذي يحمل الحقبة 11 أن يرفض بدء العمل بمجرد علمه بأن الحقبة 12 قد ألغت السلطة الأساسية.

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

لا يمكن لإعادة تشغيل النظام أن تخفض الحقبة المحفوظة.
الاستمرارية أمر بالغ الأهمية. إذا تعطل المتحكم وأعاد التشغيل، فيجب عليه استعادة أعلى حقبة أصدرها على الإطلاق. إن الرجوع إلى حقبة أقدم من شأنه أن يحيي الصلاحيات الملغاة كما لو أن إيقاف الطوارئ لم يحدث أبدًا. قم بتخزين الحقبة بشكل دائم قبل بثها. استخدم سجل الكتابة المسبقة (write-ahead log)، أو عملية fsync مؤكدة، أو مجموعة إجماع منسوخة (replicated consensus group). التاريخ يتحرك للأمام فقط.

تكرار إلغاء