Ответ
Паттерн Circuit Breaker (Автоматический выключатель) имеет три основных состояния:
Closed (Закрыто):
- Описание: Это нормальное рабочее состояние. Все запросы к защищаемому сервису проходят через Circuit Breaker без ограничений.
- Переход: Если количество ошибок или их частота превышает заданный порог (например, 5 ошибок за 10 секунд), Circuit Breaker переходит в состояние Open.
Open (Открыто):
- Описание: В этом состоянии Circuit Breaker немедленно отклоняет все запросы к защищаемому сервису, не пытаясь их выполнить. Это позволяет сервису восстановиться, избегая дальнейшей перегрузки.
- Переход: После истечения заданного таймаута (например, 30 секунд), Circuit Breaker автоматически переходит в состояние Half-Open.
Half-Open (Полуоткрыто):
- Описание: Это промежуточное состояние, в котором Circuit Breaker пропускает ограниченное количество тестовых запросов (например, один или несколько). Цель — проверить, восстановился ли защищаемый сервис.
- Переход:
- Если тестовые запросы проходят успешно, Circuit Breaker возвращается в состояние Closed.
- Если тестовые запросы снова завершаются ошибкой, Circuit Breaker немедленно возвращается в состояние Open.
Пример использования Circuit Breaker на Go с библиотекой sony/gobreaker
:
package main
import (
"fmt"
"net/http"
"time"
"github.com/sony/gobreaker"
)
func main() {
// Настройка Circuit Breaker
cb := gobreaker.NewCircuitBreaker(gobreaker.Settings{
Name: "my-external-service",
MaxRequests: 1, // В Half-Open состоянии пропускаем 1 запрос
Interval: 0, // Не используется для подсчета ошибок, если MaxRequests > 0
Timeout: 5 * time.Second, // Время, через которое переходим из Open в Half-Open
ReadyToTrip: func(counts gobreaker.Counts) bool {
// Условие для перехода в Open: 3 последовательные ошибки
return counts.ConsecutiveFailures > 2
},
OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
fmt.Printf("Circuit Breaker '%s' изменил состояние: %s -> %sn", name, from, to)
},
})
// Имитация вызова внешнего сервиса
callService := func() (interface{}, error) {
// В реальном приложении здесь был бы http.Get или другой вызов
fmt.Println("Попытка вызова внешнего сервиса...")
// Имитируем ошибку для демонстрации
if time.Now().Second()%10 < 5 { // Имитация ошибок в течение 5 секунд из 10
return nil, fmt.Errorf("ошибка внешнего сервиса")
}
return "Успешный ответ", nil
}
for i := 0; i < 20; i++ {
result, err := cb.Execute(callService)
if err != nil {
fmt.Printf("Запрос %d: Ошибка: %v (Состояние CB: %s)n", i, err, cb.State())
} else {
fmt.Printf("Запрос %d: Успех: %v (Состояние CB: %s)n", i, result, cb.State())
}
time.Sleep(1 * time.Second)
}
}
Circuit Breaker помогает повысить отказоустойчивость системы, предотвращая каскадные сбои при временной недоступности или перегрузке зависимых сервисов.