Ответ
Да, я применял паттерн Circuit Breaker (Предохранитель) в микросервисной архитектуре для повышения отказоустойчивости системы.
Что это?
Circuit Breaker — это паттерн, который предотвращает повторные вызовы потенциально неработающего сервиса. Он работает как электрический предохранитель: после определенного количества сбоев он «размыкает цепь» и перестает отправлять запросы на проблемный сервис на некоторое время, возвращая ошибку немедленно. Это защищает систему от каскадных сбоев и снижает нагрузку на отказавший компонент.
Ключевые состояния:
Closed(Замкнут): Изначальное состояние. Запросы свободно проходят к сервису. Если количество сбоев превышает порог, предохранитель переходит в состояниеOpen.Open(Разомкнут): Запросы к сервису немедленно блокируются, клиенту возвращается ошибка. По истечении тайм-аута предохранитель переходит в состояниеHalf-Open.Half-Open(Полуоткрыт): Пропускается один тестовый запрос. Если он успешен, предохранитель возвращается вClosed. Если нет — снова вOpen.
Когда использовать?
Я использовал его при взаимодействии между микросервисами, особенно для вызовов критически важных, но потенциально нестабильных зависимостей:
- Вызовы внешних API (платежные шлюзы, сервисы геолокации).
- Запросы к перегруженной базе данных или кэшу.
- Синхронное общение между внутренними сервисами.
Пример с библиотекой sony/gobreaker:
import (
"fmt"
"net/http"
"time"
"github.com/sony/gobreaker"
)
// Создаем Circuit Breaker с настройками
var cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "HTTP-GET",
MaxRequests: 1, // Количество запросов в состоянии Half-Open
Interval: 0, // Период сброса счетчиков (0 - не сбрасывать)
Timeout: 10 * time.Second, // Период, после которого состояние меняется с Open на Half-Open
ReadyToTrip: func(counts gobreaker.Counts) bool {
// Переходим в Open после 3 последовательных сбоев
return counts.ConsecutiveFailures > 3
},
})
func makeRequest() (interface{}, error) {
// Защищаем вызов внешнего сервиса
body, err := cb.Execute(func() (interface{}, error) {
resp, err := http.Get("http://example.com/api")
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode >= 500 {
return nil, fmt.Errorf("service returned error: %s", resp.Status)
}
// ... обработка успешного ответа
return []byte("OK"), nil
})
if err != nil {
// Если ошибка - это разрыв цепи, обрабатываем ее
if err == gobreaker.ErrOpenState {
fmt.Println("Circuit Breaker is open. Service is unavailable.")
}
return nil, err
}
return body, nil
} Ответ 18+ 🔞
Ах ты ж ёпта, паттерн Circuit Breaker! Да это же как раз та самая штука, которая в микросервисах от каскадного пиздеца спасает. Ну, представь, один сервис лёг, а к нему другие как давай стучаться, да стучаться, пока все вместе не накрылись медным тазом. А этот предохранитель — он как умный мужик на проходной: видит, что в цеху дым идёт, и просто говорит «всё, братва, проход закрыт, иди отсюда, пока не взорвалось».
Ну и что это за зверь такой?
Circuit Breaker — это паттерн, который не даёт тупо долбить по уже мёртвому сервису. Работает точь-в-точь как автомат в щитке: наебнулось несколько раз подряд — хлоп, и цепь разорвана. Дальше все запросы летят в пизду мгновенно, без попыток. Даёт системе передохнуть, а проблемному сервису — не умереть окончательно под лавиной запросов.
Состояния у него, блядь, как у человека:
Closed(Замкнут): Всё спокойно, трафик идёт как по маслу. Но если ошибок сверх порога — щёлк, и предохранитель вOpen.Open(Разомкнут): Полный игнор. Любой запрос получает по ебалу сразу, без диалога. «Сервис недоступен, иди нахуй». Через заданный таймаут переходит вHalf-Open, типа проверим, очухался ли.Half-Open(Полуоткрыт): Осторожно, как на минное поле, пропускаем один пробный запрос. Прошёл — ура, закрываем цепь. Снова наебнулся — ну всё, опять вOpen, сиди дальше.
Где я это применял?
Да везде, где есть хоть тень сомнения в надёжности соседа! Особенно:
- Вызовы к внешним API, которые могут в любой момент сказать «пошёл нахуй, я в отпуске».
- Обращения к базе, которая уже еле дышит от нагрузки.
- Любое синхронное общение между нашими же сервисами, когда один начинает тупить.
Вот, смотри, как на Go с библиотекой sony/gobreaker выглядит:
import (
"fmt"
"net/http"
"time"
"github.com/sony/gobreaker"
)
// Настраиваем нашего сторожа
var cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "HTTP-GET",
MaxRequests: 1, // В состоянии Half-Open пропустит только один запрос на разведку
Interval: 0, // Не сбрасываем счётчики со временем
Timeout: 10 * time.Second, // Через 10 секунд после Open попробуем Half-Open
ReadyToTrip: func(counts gobreaker.Counts) bool {
// Если три раза подряд обосрались — всё, концерт окончен, размыкаем цепь.
return counts.ConsecutiveFailures > 3
},
})
func makeRequest() (interface{}, error) {
// Оборачиваем наш рискованный вызов
body, err := cb.Execute(func() (interface{}, error) {
resp, err := http.Get("http://example.com/api")
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode >= 500 {
// Сервер сам сказал, что он — манда с ушами
return nil, fmt.Errorf("service returned error: %s", resp.Status)
}
// ... если всё ок, обрабатываем ответ
return []byte("OK"), nil
})
if err != nil {
// Если ошибка — это потому что цепь разомкнута
if err == gobreaker.ErrOpenState {
fmt.Println("Circuit Breaker is open. Service is unavailable.")
}
return nil, err
}
return body, nil
}
Вот и весь сказ. Просто, а эффективно, как удар кирпичом по голове. Система перестаёт героически пытаться достучаться до трупа и начинает жить своей жизнью, пока тот не очухается. Ёперный театр, а не паттерн!