Какие знаешь состояния Circuit Breaker?

Ответ

Паттерн Circuit Breaker (Автоматический выключатель) имеет три основных состояния:

  1. Closed (Закрыто):

    • Описание: Это нормальное рабочее состояние. Все запросы к защищаемому сервису проходят через Circuit Breaker без ограничений.
    • Переход: Если количество ошибок или их частота превышает заданный порог (например, 5 ошибок за 10 секунд), Circuit Breaker переходит в состояние Open.
  2. Open (Открыто):

    • Описание: В этом состоянии Circuit Breaker немедленно отклоняет все запросы к защищаемому сервису, не пытаясь их выполнить. Это позволяет сервису восстановиться, избегая дальнейшей перегрузки.
    • Переход: После истечения заданного таймаута (например, 30 секунд), Circuit Breaker автоматически переходит в состояние Half-Open.
  3. 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 помогает повысить отказоустойчивость системы, предотвращая каскадные сбои при временной недоступности или перегрузке зависимых сервисов.