الگوی Circuit Breaker در ارتباطات میان سرویس ها

نیاز ارتباط با سرویس های دیگر در داخل هر نرم افزاری یک امر اجتناب ناپذیر و معمول هست. تفاوت مهم ارتباطات داخلی با ارتباط با سرویس های خارجی این هست که ممکن هست درخواست ما با خطا مواجه شود یا کلا پاسخی دریافت نکند. حالا اگه سرویس ما کاربران زیادی داشته باشد این انتظار های طولانی برای دریافت جواب باعث می شود منابع سخت افزاری سرویس ما پر شده و سرویس ما هم نیز دیگر توان پاسخ به درخواست های دیگران را نداشته باشد. حالا اگر سرویس دیگری به سرویس ما وابسته باشد به همین طریق آن سرویس نیز توان پاسخ گویی خودش را از دست می دهد و همینطور مانند دومینو همه سرویس ها از کار می افتند. در این جا Circuit Breaker به کمک ما می آید.

الگوی Circuit Breaker چیست ؟

روش کار در circuit breaker ساده است. تمام ارتباطات ما با سرویس های دیگر باید از circuit breaker ما رد شود، که بتواند خطا ها را کنترل می کند. هنگامی که خطا ها به یک تعداد مشخص رسید، circuit breaker جریان را متوقف می کند و تمام ارتباطات بعدی با circuit breaker بدون اینکه ارتباطی برقرار شود، با خطا بر می گردند.

انواع وضعیت در Circuit Breaker

قطع کننده مدار دارای سه وضعیت است: بسته (Close)، باز (Open) و نیمه باز (Half-Open)

بسته (Close): وقتی همه چیز عادی است، circuit breaker در حالت بسته باقی مانده و تمام ارتباطات به سرویس ها منتقل می شوند. هنگامی که تعداد خرابی ها از یک تعداد از پیش تعیین شده بیشتر شود، circuit breaker به حالت Open می رود.

باز (Open): در این وضعیت circuit breaker برای ارتباطات بدون اجرای واقعی ارتباط، خطا برمی گرداند.

حالت نیمه باز (Half-Open): پس از مدت زمانی circuit breaker به حالت نیمه باز سوئیچ می شود تا وجود خطا را بررسی کند. اگر در این حالت تنها یک ارتباط خراب شود، یکبار دیگر circuit breaker قطع می شود. در صورت موفقیت ، circuit breaker مجدداً به حالت بسته و طبیعی بر می گردد.


پیاده سازی در Golang

این الگوی در Golang را میتوان با استفاده از gobreaker به شکلی ساده پیاده سازی کرد.

ابتدا با دستور زیر gobreaker را دریافت می کنیم.

go get github.com/sony/gobreaker

اگه بخوایم تکه کد بالا رو بررسی کنیم در خط ۲ برای broker یک نام انتخاب کردیم.

‍‍st.Name = &quotHTTP GET&quot


در خط بعدی (۳) با یک تابع مشخص کردیم در چه صورت circuit breaker ما باز شود و دیگر ریکوست از آن عبور نکند.

‍‍st.ReadyToTrip = func(counts gobreaker.Counts) bool {
   failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
   return counts.Requests >= 3 && failureRatio >= 0.6
}

که در این مثال ما یک نسبت ریکوست هایی که موفق نشد به تعداد کل گرفتیم که اگه 60 درصد یا بیشتر ریکوست ها موفق نشده باشند circuit breaker باز شود و دیگر ریکوست زده نشود.


در خط ۸ ام به بعد تنظیماتی که انجام دادم رو برای gobreaker ارسال میکنیم و تابع ارسال درخواست http خودمان را می نویسیم

cb = gobreaker.NewCircuitBreaker(st)
body, err := cb.Execute(func() (interface{}, error) {
   resp, err := http.Get(&quothttp://example.com&quot)
   if err != nil {
      return nil, err
   }
   return resp, nil
})

این یک مثال ساده از پیاده سازی circuit breaker در Golang بود این پترن در زبان های دیگر هم پیاده سازی شده که میتونید از آن ها استفاده کنید.

gobreaker github: https://github.com/sony/gobreaker


منابع: