المستوى: متوسط — يفترض هذا المقال أنك تعرف أساسيات الـ microservices واستدعاءات HTTP بين الخدمات. لو لسه مبتدئ تماماً، المثال الأول هيوصّلك الفكرة قبل الجزء التقني.
Circuit Breaker: امنع خدمة واحدة بطيئة من إسقاط نظامك بالكامل
لو خدمة دفع واحدة بطيئة قدرت توقّع 8 خدمات معاها في أقل من 30 ثانية، المشكلة مش في الخدمة البطيئة نفسها. المشكلة إن مفيش حاجة بتقطع النزيف. نمط Circuit Breaker بيعزل الخدمة العاطلة في ملي ثانية، ويحافظ على باقي النظام شغّال بدل ما ينهار بالكامل.
المشكلة باختصار
تخيل عندك خدمة checkout بتنادي خدمة payment عبر HTTP. الـ timeout متظبّط على 5 ثوانٍ. فجأة خدمة الدفع بقت بطيئة وبتاخد 5 ثوانٍ في كل طلب قبل ما تفشل.
اللي بيحصل فعلاً: كل request جاي على checkout بيفتح thread ويستنى 5 ثوانٍ. لو عندك thread pool بـ 200 thread وبيوصلك 100 طلب/ثانية، الـ pool بيتملي في تانيتين. بعد كده checkout نفسها بقت مش بترد، رغم إن المشكلة الأصلية في خدمة تانية. ده اسمه cascading failure — الفشل بيتنقّل من خدمة لخدمة لحد ما النظام كله يقع.
الفكرة بمثال قبل التقنية
في بيتك فيه قاطع كهرباء (الطبلون). لو حصل short circuit في جهاز، القاطع بيفصل الدايرة دي فوراً. ليه؟ عشان ميسيبش التيار الزايد يحرق أسلاك البيت كله ويوصل لحريق. القاطع بيضحّي بجهاز واحد عشان ينقذ البيت.
الفصل ده مش دائم. انت بتصلّح العطل، وبعدين بترفع القاطع تاني. ولو رفعته وفصل تاني على طول، معناه العطل لسه موجود فبتسيبه مفصول.
دلوقتي الكلام العلمي: نمط Circuit Breaker، اللي وثّقه Michael Nygard في كتاب Release It! ونشره Martin Fowler، بيعمل بالظبط نفس الفكرة حوالين أي استدعاء خارجي. بيلفّ الاستدعاء في كائن (proxy) بيراقب نسبة الفشل. لو النسبة عدّت حد معين، الـ breaker "بيفتح" ويرفض الطلبات فوراً بدل ما يستنى timeout كل مرة.
الحالات الثلاث: Closed و Open و Half-Open
الـ Circuit Breaker عنده 3 حالات، وده قلب الموضوع:
- Closed (مغلق): الوضع الطبيعي. كل الطلبات بتعدّي للخدمة. الـ breaker بيعدّ نسبة الفشل في الخلفية.
- Open (مفتوح): لما نسبة الفشل تعدّي الحد (مثلاً 50%)، الدايرة بتفتح. أي طلب جديد بيترفض فوراً (fail fast) من غير ما يلمس الخدمة العاطلة أصلاً. هنا بنرجّع fallback أو خطأ سريع.
- Half-Open (نصف مفتوح): بعد فترة انتظار (مثلاً 30 ثانية)، الـ breaker بيسمح بعدد محدود من الطلبات التجريبية. لو نجحت، بيرجع Closed. لو فشلت، بيرجع Open تاني ويستنى من جديد.
الفرق العملي ضخم: من غير breaker، كل طلب فاشل بياخد 5 ثوانٍ. مع breaker مفتوح، الطلب بيترفض في أقل من 1 ملي ثانية. يعني الـ P99 latency للطلبات دي بينزل من 5,000ms لـ أقل من 5ms، والـ threads بتفضل فاضية لباقي الشغل.