ذات مرة، بدأت واجهة برمجية (API) لأحد مزوّدي المدفوعات تستجيب في ثماني ثوانٍ بدلاً من ثمانين مِلّي ثانية. لم تكن معطّلة، بل بطيئة فحسب. وخلال أربع دقائق توقّفت تماماً خدمة إتمام الشراء التي ظلّت تعمل عامين دون عطل واحد. تكدّست خيوط المعالجة (threads) في انتظار خدمة لم تقل لا قطّ، لكنها لم تقل نعم بالسرعة الكافية.
هذا هو نمط الفشل الذي تغفل عنه معظم الفرق: الخدمة البطيئة، لا الميّتة. نصمّم للمسار المثالي، ونضيف موازِن حِمل (load balancer)، ثم نصف النظام بأنه مرن. لكن المرونة ليست منتجاً تشتريه، بل مجموعةُ قراراتٍ حول سلوك نظامك حين يتعطّل أحد أجزائه — وذلك واقعٌ حتميّ لا مجرّد احتمال.
الفشل هو الأصل، لا الاستثناء
ما إن تتجاوز الخادم الواحد حتى يكون ثمة دائماً شيء معطّل جزئياً: قرص يمتلئ، عُقدة تُعيد التشغيل، وصلة شبكة تُسقط رزمة من كل ألف. لنُجرِ الحساب: طلبٌ يمرّ عبر 30 خدمة، كلٌّ منها متاحة بنسبة 99.95%، يبلغ معدّل نجاحه في أفضل الأحوال نحو 98.5% — أي إن طلباً واحداً تقريباً من كل 65 يصطدم بخدمة متدهورة. وعند مليون طلب يومياً، يتحوّل ذلك إلى عددٍ كبير من المستخدمين الغاضبين.
التحوّل الجوهري تحوّلٌ ذهنيّ في المقام الأول. توقّف عن سؤال «كيف أمنع هذا من الفشل؟»، وابدأ بسؤال «حين يفشل هذا، ماذا يحدث بعده؟». وكل ما يلي ينبع من هذا السؤال.
الأنماط التي تستحقّ عناءها
لست بحاجة إلى شبكة خدمات (service mesh) ولا إلى شهادة دكتوراه. أربعة أنماط تكفي لاحتواء معظم نطاق الضرر:
- مهلة زمنية (timeout) لكل نداء شبكي. المهلة الافتراضية في معظم عملاء HTTP لا نهائية عملياً، وهكذا تستنزف خدمةٌ بطيئةٌ واحدة مجمَّع الخيوط لديك بأكمله. اضبط مُهَلاً صريحة وصارمة، واجعلها أقصر من مهلة المستدعي، كي تظهر الأعطال عند الحافة بدل أن تتراكم في المنتصف.
- إعادة المحاولة مع تراجع أُسّي (backoff) وتشويش (jitter). إعادة المحاولة الساذجة تحوّل التعثّر إلى انقطاع كامل: فما إن تتعافى الخدمة حتى ينهال عليها العملاء جميعاً دفعة واحدة. التراجع الأُسّي يباعد بين المحاولات، والتشويش العشوائي يمنعها من التزامن في «قطيع هائج» (thundering herd). ولا تُعِد أبداً محاولة عملية كتابة غير مُتماثِلة (non-idempotent) على نحوٍ أعمى.
- قواطع الدائرة (circuit breakers). حين تتعطّل خدمة تعطّلاً واضحاً، توقّف عن مناداتها. يفصل القاطع بعد عددٍ من الإخفاقات، ويفشل سريعاً خلال فترة تهدئة، ثم يسمح بمرور قدرٍ ضئيل من الحركة لجسّ النبض. وهذا يحميك ويحمي الخدمة التي كنت ستُغرقها بالطلبات وهي تحاول التعافي.
- عزل الموارد (bulkheads). افصل الموارد كي لا تُغرِق خدمةٌ واحدة السفينة بأكملها. فمجمَّعات خيوطٍ أو اتصالاتٍ منفصلة لكل خدمة خلفية تعني أن نداءً عالقاً لخدمة التوصيات لا يمكنه أن يحرم مسار الدفع من عمّاله.
تدهورْ عن قصد
الهدف ليس «ألّا تفشل أبداً»، بل «أن تفشل بطريقة يكاد المستخدم لا يلاحظها». هذا هو التدهور المتدرّج (graceful degradation)، وهو قرارٌ يخصّ المنتج بقدر ما يخصّ الهندسة.
قدّم بياناتٍ قديمة نسبياً من الذاكرة المؤقتة (cache) حين يتعذّر الوصول إلى المصدر الموثوق. اعرض توصيات عامة بدل رفٍّ فارغ. ضَع عملية كتابة غير حرجة في طابور وأكّدها لاحقاً. وضَعْ أعلام ميزات (feature flags) أمام الأعمال المكلفة والاختيارية كي تُخفّف الحِمل تحت الضغط بإطفاء بعض المزايا بدل أن ينهار كل شيء. في تجربتي، أسرع الفرق تعافياً هي التي قرّرت مسبقاً أيُّ الميزات حاملةٌ للبنية وأيُّها زينة.
لا مرونة لديك حتى تكسر نظامك بنفسك
التحويل الاحتياطي (failover) الذي لم يُختبَر قطّ ليس شبكة أمان، بل مجرّد نظرية. رأيتُ نسخة قاعدة بيانات موثّقة بإتقان تظلّ بلا استخدام عاماً كاملاً، ثم تفشل ترقيتُها في العطل الوحيد الذي بُنيت له، لأن إعداداً ما انحرف في صمت.
التحويل الاحتياطي غير المختبَر ليس إلا أملاً مرفقاً بملف YAML.
عالِج ذلك بالتمرين. نفّذ «أيام محاكاة» (game days): خصّص ساعة، وأوقف عُقدة في بيئة الاختبار (أو الإنتاج إن كنت جريئاً ومستعداً)، وراقب ما يحدث فعلاً. واحقِن تأخيراً، لا انقطاعاً فقط — فالبطء أصعب من الموت. واختبر الحِمل إلى ما بعد ذروتك المتوقّعة كي تعرف موضع الهاوية قبل أن يجده عملاؤك نيابةً عنك.
من أين تبدأ يوم الاثنين
لا تحاول إصلاح كل شيء دفعةً واحدة. اختر أهمّ مسار مستخدم لديك — ذلك الذي يكلّفك مالاً أو ثقة حين يتوقّف. ثم:
- ارسم خريطة اعتمادياته، وضَعْ مهلة صريحة على كل واحدة منها.
- أضِف لإعادة المحاولة تراجعاً أُسّياً مع تشويش، وقاطعَ دائرةٍ واحداً حول أقلّ خدماتك موثوقية.
- قرّر على الورق كيف ينبغي أن يتدهور هذا المسار — وابنِ الخطة البديلة.
- نفّذ «يوم محاكاة» مدته 60 دقيقة هذا الشهر لتثبت أنه يعمل فعلاً.
المرونة ليست محطة تبلغها، بل عضلة تواصل تدريبها. والسؤال الجدير بالتأمل هذا الأسبوع: لو أصبحت أهمّ خدماتك بطيئةً الآن — لا مفقودة، بل بطيئة فحسب — فهل سيلاحظ مستخدموك ذلك أصلاً؟