كيف وصلنا إلى نشر بلا أي خطأ 502
في كل مرة كنا ننشر الواجهة الخلفية لـ Mythex، كانت بعض الطلبات تفشل بخطأ 502 Bad Gateway. ليست كثيرة، لكن خطأ 502 أثناء النشر يعني أن نقرة أحدهم لم تفعل شيئاً، أو أن بناءً كان يراقبه توقف لحظة. تتبعنا المشكلة إلى مشكلتين منفصلتين: مراقب ذاتي الإصلاح كان يتصارع مع نشراتنا، وفجوة بين لحظة توقف الخادم عن الاستماع ولحظة توقف موازن الحمل عن إرسال الحركة إليه. وعبر ثلاثة عمليات نشر إنتاجية متتالية بعد الإصلاحات، انخفض العدد من 10 إلى 6 ثم إلى 0.
الإعداد
تعمل واجهتنا البرمجية والمنسّق كحاويات على مجموعة صغيرة من الخوادم خلف موازن حمل من AWS من نوع Application Load Balancer (ALB). ينشر النشر خادماً واحداً في كل مرة: يُفرغ الحاويات القديمة، ويشغّل الجديدة، ثم ينتقل للتالي. ويوجد مراقب على كل خادم يتحقق من أن الحاويات تعمل، ويعيد تشغيل أي حاوية متوقفة، ووجوده لكي تعود عملية تعطلت الساعة الثالثة فجراً دون أن يستيقظ أحد.
كلاهما معقول وحده. لكنهما معاً لم يكونا كذلك.
المشكلة الأولى: المراقب يسابق النشر
كان المراقب يعمل مرة في الدقيقة، ويعالج الخلل بعد فحص فاشل واحد. والنشر يُفرغ الخدمات عمداً لمدة تصل إلى 150 ثانية، وخلالها يُفترض أن يفشل فحص الصحة. فكان المراقب يتدخل في كل نشر.
وفي معظم الأحيان كان يخسر السباق دون ضرر. لكن مرة واحدة ربح: أعاد كتابة ملف Compose (الوصف الذي يحدد أي الحاويات يجب أن تعمل) في منتصف النشر، فترك خادماً دون حاوية البوابة نهائياً، بينما أبلغت مهمة النشر بالنجاح.
الإصلاحات:
- قفل واحد. يأخذ النشر الآن قفل الملف نفسه الذي يأخذه سكربت تهيئة الخادم، فلا يعمل المراقب والنشر في الوقت نفسه أبداً.
- أربع إنذارات، لا واحد. يحتاج المراقب إلى أربعة فحوصات فاشلة متتالية قبل أن يتصرف. الخدمة التي تُفرَّغ لم تعد تبدو ميتة.
- تعريف واحد. لملف Compose مصدر واحد فقط، يُنشر إلى الخوادم، بدلاً من نسخ يمكن أن تتباعد.
- تحقق، لا تثق. لم يعد مهمة النشر تنجح لأن أمراً أعاد رمزاً ما. بل يتحقق من واجهة برمجة كل خادم والمنسّق والبوابة وعامل النشر قبل أن يستطيع النجاح.
المشكلة الثانية: الخادم غادر قبل أن تغادر الحركة
كانت المشكلة الثانية أهدأ. عندما يُفرغ النشر خادماً، يبدأ الخادم بالرد على نقطة فحص الصحة الخاصة به بالرمز 503 ليخرجه موازن الحمل من التوزيع. وقد فعل ذلك لمدة 5 ثوانٍ، ثم أغلق نفسه.
لكن ALB كان يفحص الصحة على فترات، ويحتاج إلى عدة فحوصات فاشلة متتالية قبل أن يتوقف عن توجيه الحركة إلى الهدف، أي حتى نحو 60 ثانية من البداية إلى النهاية. فكان موازن الحمل لنحو 55 ثانية يواصل إرسال طلبات حقيقية إلى خادم توقف فعلياً عن الاستماع. وكانت تلك هي أخطاء 502 لدينا.
كان الإصلاح في جعل الجدولين الزمنيين يتفقان:
- تفحص مجموعة الأهداف الآن كل 5 ثوانٍ، وتعلّم الهدف غير صحي بعد فشلين، أي نحو 10 ثوانٍ للاكتشاف.
- يستمر التفريغ في خدمة الحركة الحقيقية لمدة 15 ثانية بعد أن يبدأ فشل فحوصات الصحة، فيكون هناك تداخل دائماً.
- هذه الإعدادات تعيش في السكربت الذي يهيّئ البنية التحتية، لا في لوحة تحكم نقر عليها أحدهم مرة واحدة.
جعل الأرقام تحفظ بعضها
تعتمد المهلات بعضها على بعض. يجب أن يتجاوز التفريغ الوقت الذي يحتاجه الموازن لملاحظة التغيير؛ ويجب أن ينتهي التفريغ زائداً الإيقاف قبل أن تُقتل الحاوية قسراً. من السهل أن يغيّر أحدهم رقماً واحداً بعد ستة أشهر فيعيد المشكلة دون قصد.
لذلك كتبنا هذه العلاقات كاختبارات: يجب أن يكون التفريغ أطول من فاصل فحص الصحة مضروباً في عتبة الفشل؛ ويجب أن يبقى الوقت اللازم لاستعادة الصحة قصيراً؛ ويجب أن يتسع التفريغ كله داخل مهلة الإيقاف الممنوحة للحاوية. غيّر رقماً واحداً دون البقية وسيفشل CI. واختبرنا الاختبارات نفسها بالطفرات: غيّرنا كل رقم إلى قيمة خاطئة وتحققنا من أن أحد الاختبارات يلتقطها.
قياس النشر أمر سهل الخطأ
كان قياسنا الأول يقول إن النشر النظيف مكسور بنحو 3%. لم يكن كذلك. كنا نعد كل استجابة غير 200، و503 من نقطة فحص صحة أثناء التفريغ ليس فشلاً، بل هو التفريغ يقوم بعمله، يخبر الموازن ألا يختار ذلك الخادم بينما يواصل خدمة الطلبات الحقيقية.
ما يشعر به المستخدمون هو 502: طلب لم يصل إلى شيء. وعدّ هذه وحدها أعطانا الصورة الحقيقية: 10، ثم 6، ثم 0 عبر ثلاثة عمليات نشر إنتاجية.
ما الذي استخلصناه
- الإصلاح الذاتي يحتاج إلى معرفة بالتوقف المخطط. مراقب لا يستطيع التمييز بين النشر والعطل سيتصارع مع النشر عاجلاً أم آجلاً.
- التفريغ مصافحة. يجب أن يستمر الخادم في الخدمة حتى يتأكد الموازن من توقفه عن إرسال الحركة، وهذا التوقيت يُضبط على الموازن، لا على الخادم.
- رمّز الثوابت كاختبارات. الأرقام التشغيلية تنحرف. الاختبارات التي تربطها ببعضها لا تنحرف.
- قرر ما الذي تقيسه قبل القياس. «الأخطاء» كانت المقياس الخاطئ؛ «الطلبات التي لم تصل إلى شيء» كانت المقياس الصحيح.
إذا كنت تنشر تطبيقاً على Mythex، فلن ترى أياً من هذا، وهذا هو المقصود. ذو صلة: كيف يبقى تطبيقك المنشور متاحاً أثناء إعادة نشره.