الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
DevOps بالعربي

قاطع الدائرة Circuit Breaker: امنع فشل خدمة واحدة من إسقاط نظامك كله

متوسط30 يوليو 20266 دقائق قراءة
قاطع الدائرة Circuit Breaker: امنع فشل خدمة واحدة من إسقاط نظامك كله

هذا المقال يتطلب مستوى: متوسط. تحتاج تكون تعاملت قبل كده مع خدمة بتنادي خدمة تانية (API داخلي أو خارجي)، وتعرف يعني إيه timeout وthread pool. لو لسه مبتدئ، فيه مثال بسيط في الأول هيوصّلك الفكرة قبل الشرح التقني.

قاطع الدائرة Circuit Breaker: امنع فشل خدمة واحدة من إسقاط نظامك كله

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

المشكلة باختصار

تخيّل خدمة الدفع عندك بطؤت فجأة من 200 مللي ثانية لـ 8 ثواني. كل طلب دلوقتي بيحجز thread وهو مستني الرد. الـ thread pool عندك سعته 200 thread. في أقل من نص دقيقة كل الـ threads اتحجزت وهي بتستنى الدفع. النتيجة: مش خدمة الدفع بس اللي وقعت، الموقع كله وقف — حتى الصفحات اللي مالهاش علاقة بالدفع. ده اسمه الانهيار المتسلسل (cascading failure). عطل في مكان واحد بيسحب معاه النظام كله.

الطريقة الشائعة إنك تعتمد على الـ timeout بس. المشكلة إن الـ timeout بيفشل بعد انتظار. لو الـ timeout 8 ثواني، يبقى كل طلب بيضيّع 8 ثواني قبل ما يستسلم، وخلال الوقت ده الـ threads بتتراكم. الافتراض هنا إن عندك dependency (خدمة تعتمد عليها) وارد إنها تبطأ أو تفشل.

الفكرة الأساسية: زي القاطع الكهربائي في بيتك

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

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

إزاي بيشتغل علميًا: ثلاث حالات

قاطع الدائرة عبارة عن آلة حالات (state machine) بسيطة بثلاث حالات. الصورة دي بتلخّص الانتقالات بينها:

  • CLOSED (مغلق): الوضع الطبيعي. الطلبات بتعدّي للخدمة عادي. القاطع بيعدّ نسبة الفشل في الخلفية.
  • OPEN (مفتوح): لما الفشل يعدّي الحد (مثلاً 5 حالات متتالية أو 50% فشل في نافذة زمنية)، القاطع بيتفتح. كل طلب جديد بيترفض فورًا بدون ما يلمس الخدمة، في أقل من مللي ثانية. ده الـ fail fast.
  • HALF-OPEN (نصف مفتوح): بعد فترة تهدئة (مثلاً 30 ثانية)، القاطع بيسمح بطلب اختبار واحد يعدّي. لو نجح، معناه الخدمة رجعت، فيرجع CLOSED. لو فشل، يرجع OPEN تاني ويستنى فترة كمان.

مثال تنفيذي: قاطع دائرة في Python من الصفر

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

Python
import time

class CircuitBreaker:
    def __init__(self, fail_max=5, reset_timeout=30):
        self.fail_max = fail_max          # عدد الأخطاء قبل الفتح
        self.reset_timeout = reset_timeout  # ثواني قبل المحاولة
        self.failures = 0
        self.state = "CLOSED"
        self.opened_at = 0

    def call(self, func, *args):
        if self.state == "OPEN":
            if time.time() - self.opened_at >= self.reset_timeout:
                self.state = "HALF_OPEN"   # وقت نجرّب تاني
            else:
                raise Exception("Circuit OPEN - رفض فوري")  # fail fast

        try:
            result = func(*args)
        except Exception:
            self.failures += 1
            if self.failures >= self.fail_max:
                self.state = "OPEN"
                self.opened_at = time.time()
            raise

        # نجح الطلب: نرجّع الوضع طبيعي
        self.failures = 0
        self.state = "CLOSED"
        return result

الفكرة كلها في سطر raise Exception("Circuit OPEN"): بدل ما تستنى 8 ثواني علشان تفشل، بتفشل في أقل من مللي ثانية. الفرق ده هو اللي بينقذ الـ thread pool من الامتلاء.

الأرقام: قبل وبعد

في السيناريو اللي فوق، من غير قاطع دائرة: 200 thread اتحجزت في ~25 ثانية، وزمن الاستجابة قفز من 200ms لـ 8000ms، والموقع كله وقع. مع قاطع دائرة بحد 50% فشل ونافذة 10 ثواني: بعد أول موجة فشل بيتفتح القاطع، فالطلبات الجديدة بترجع خطأ في أقل من 1ms، والـ threads بتفضل متاحة لباقي الخدمات. النتيجة إن صفحات المنتجات والبحث فضلت شغّالة، وخدمة الدفع بس هي اللي ظهرت برسالة "مؤقتًا غير متاح". الأرقام دي تقديرية وبتختلف حسب حجم الـ pool وزمن الـ timeout عندك، بس النمط ثابت.

الـ trade-offs وما يجب الانتباه له

كل توصية معاها ثمنها. قاطع الدائرة بيكسّبك عزل الفشل ومنع الانهيار المتسلسل واستجابة سريعة وقت العطل. بتخسر مقابلها:

  • تعقيد إضافي: محتاج تضبط الحدود (نسبة الفشل، حجم النافذة، مدة التهدئة)، وضبط غلط ممكن يفتح القاطع بدري أو متأخر.
  • لازم منطق بديل (fallback): لما القاطع يفتح، هترجّع إيه للمستخدم؟ قيمة من الكاش؟ رسالة مؤدبة؟ لو مفيش بديل معقول، القيمة بتقل.
  • احتمال رفض طلبات كانت هتنجح: القاطع المفتوح بيرفض الكل، حتى لو الخدمة رجعت في نص الفترة. ده false positive مقبول عادةً مقابل حماية النظام.

ونقطة مهمة: قاطع الدائرة مش بديل عن الـ timeouts ولا الـ retries مع backoff. الثلاثة بيشتغلوا مع بعض. القاطع بيحميك من الفشل المستمر، والـ timeout بيحدد متى الطلب الواحد يعتبر فاشل.

متى لا تستخدم هذه الطريقة

مش كل استدعاء محتاج قاطع دائرة. متستخدمهوش لو:

  • الاستدعاء محلي وسريع دايمًا (in-process) ومفيهوش شبكة — مفيش حاجة تتعزل أصلاً.
  • الخدمة اللي بتناديها نادر جدًا تفشل وعندها SLA عالي، فالتعقيد الزيادة مالوش عائد.
  • الفشل لازم يوصل للمستخدم على أي حال ومفيش fallback ممكن — هنا القاطع بيضيف طبقة من غير فايدة حقيقية.

الخطوة التالية

افتح أهم خدمة عندك بتعتمد على dependency خارجي، ولفّها بمكتبة قاطع دائرة جاهزة: resilience4j لو Java، Polly لو .NET، pybreaker لو Python. ابدأ بحد 50% فشل ونافذة 10 ثواني ومدة تهدئة 30 ثانية. بعدين شغّل اختبار حمل توقّف فيه الـ dependency (اقفل الخدمة يدويًا)، وشوف: النظام بيرجّع خطأ سريع ولا بيتعلّق لحد ما الـ threads تخلص؟ لو اتعلّق، القاطع مش مظبوط؛ راجع الحدود.

لو عندك بنية microservices على Kubernetes، ممكن كمان تعمل ده على مستوى الشبكة عبر service mesh زي Istio أو Envoy (اسمها هناك outlier detection) بدون ما تلمس كود التطبيق.

المصادر

  • Michael T. Nygard, كتاب "Release It!" — النمط الأصلي لقاطع الدائرة (Stability Patterns).
  • Martin Fowler, مقال "CircuitBreaker" على martinfowler.com — شرح الحالات الثلاث والانتقالات.
  • توثيق resilience4j الرسمي (resilience4j.readme.io) — إعدادات failure rate وsliding window وwait duration.
  • Microsoft Azure Architecture Center — "Circuit Breaker pattern"، ومكتبة Polly للـ .NET.
  • Amazon Builders' Library — "Timeouts, retries, and backoff with jitter" لعلاقة القاطع بالـ retries.
  • Netflix Hystrix (الآن في وضع الصيانة) — المرجع التاريخي لتطبيق النمط على نطاق واسع.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة