Вопрос 5 · Раздел 17

Что такое паттерн Circuit Breaker

Cascade failure (цепной сбой): сервис A ждёт сервис B, сервис C ждёт A — все потоки зависают, и вся система падает.

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

Circuit Breaker (предохранитель) — паттерн, который защищает сервис от вызова неработающего зависимого сервиса.

Аналогия из жизни: электрический предохранитель отключает ток при перегрузке, чтобы не сгорела проводка.

Три состояния:

  1. CLOSED — обычный режим, вызовы проходят
  2. OPEN — вызовы блокируются (сервис “сломан”)
  3. HALF-OPEN — пробный вызов (проверка, починили ли сервис)
Сервис A → Сервис B (работает)
              ↓ (начал тормозить)
Circuit Breaker → OPEN (блокирует вызовы)
              ↓ (подождали, проверка)
Circuit Breaker → HALF-OPEN → один вызов для проверки
              ↓ (успех!)
Circuit Breaker → CLOSED (снова работает)

🟡 Middle Level

Как работает

// Резилиент4j (Resilience4j)
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)  // 50% — компромисс: не открываем от одной случайной ошибки.
    // slidingWindowSize=10, minimumNumberOfCalls=5: нужно минимум 5 вызовов,
    // и если 50%+ из них FAILED — breaker открывается.
    .waitDurationInOpenState(Duration.ofSeconds(10))  // ждать 10 сек
    .slidingWindowSize(10)  // последние 10 вызовов
    .build();

CircuitBreaker circuitBreaker = CircuitBreaker.of("backend", config);

// Использование
Supplier<String> decorated = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> backendService.call());

Try.of(decorated)
    .onSuccess(result -> process(result))
    .onFailure(error -> fallback());

Когда использовать

✅ Circuit Breaker нужен когда:

  • Внешний сервис может быть недоступен
  • Сетевые проблемы (timeout, connection refused)
  • Нужно защитить свой сервис от cascade failure

Cascade failure (цепной сбой): сервис A ждёт сервис B, сервис C ждёт A — все потоки зависают, и вся система падает.

❌ Circuit Breaker не нужен когда:

  • Вызов всегда быстрый и надёжный
  • Внутренние вызовы в одном процессе

Типичные ошибки

  1. Слишком агрессивный threshold:
    failureRateThreshold = 10% → OPEN после 1 ошибки из 10
    Слишком много false positives
    

🔴 Senior Level

Internal Implementation

State transitions:

CLOSED → OPEN: failure rate > threshold
OPEN → HALF-OPEN: wait duration elapsed
HALF-OPEN → CLOSED: success call
HALF-OPEN → OPEN: failure call

Sliding window:

COUNT-based: последние N вызовов
TIME-based: вызовы за последние T секунд

Resilience4j поддерживает оба типа

Архитектурные Trade-offs

Подход Плюсы Минусы
Circuit Breaker Быстрый fallback, потому что не тратит время на ожидание timeout от неработающего сервиса — сразу возвращает заглушку. Сложная настройка
Retry Пробует снова Может усугубить проблему
Timeout Защита от зависания Не защищает от ошибок

Production Experience

Spring Boot + Resilience4j:

@CircuitBreaker(name = "backend", fallbackMethod = "fallback")
@Retry(name = "backend")
@TimeLimiter(name = "backend")
public CompletableFuture<String> callBackend(String input) {
    return backendService.callAsync(input);
}

public CompletableFuture<String> fallback(String input, RuntimeException ex) {
    return CompletableFuture.completedFuture("fallback: " + input);
}

Configuration:

resilience4j:
  circuitbreaker:
    instances:
      backend:
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 3
        minimumNumberOfCalls: 5

Best Practices

✅ Настраивайте threshold по метрикам
✅ Используйте fallback для graceful degradation
✅ Мониторьте состояние Circuit Breaker
✅ Комбинируйте с Retry и Timeout

❌ Не используйте слишком низкий threshold
❌ Не игнорируйте HALF-OPEN состояние
❌ Не используйте без fallback

🎯 Шпаргалка для интервью

Обязательно знать:

  • Circuit Breaker защищает от cascade failure, блокируя вызовы к неработающему сервису
  • Три состояния: CLOSED (норма), OPEN (блокировка), HALF-OPEN (проверка)
  • Переход CLOSED→OPEN при превышении failure rate threshold (обычно 50%)
  • OPEN→HALF-OPEN после wait duration (10-60 сек), HALF-OPEN→CLOSED при успехе
  • Sliding window (10-100 вызовов) для статистически значимой выборки
  • Всегда комбинируйте с fallback для graceful degradation
  • Resilience4j — стандартная библиотека для Java/Spring

Частые уточняющие вопросы:

  • Почему 50% threshold? Компромисс: не открываем от одной случайной ошибки, но и не ждём пока всё упадёт.
  • Зачем HALF-OPEN? Проверить, починился ли сервис, прежде чем восстановить полный трафик.
  • Чем Circuit Breaker лучше простого timeout? Timeout защищает от зависания, но не от cascade failure — CB сразу возвращает fallback, не тратя время.
  • Как считать failure rate? Sliding window: последние N вызовов или вызовы за T секунд.

Красные флаги (НЕ говорить):

  • “Circuit Breaker = Retry” — нет, CB блокирует, Retry пробует снова
  • “Threshold 10% — надёжность” — нет, будет много false positives
  • “CB не нужен для внутренних сервисов” — cascade failure возможен везде
  • “HALF-OPEN можно пропустить” — без него не узнать, починился ли сервис

Связанные темы:

  • [[6. Как работает Circuit Breaker и какие у него состояния]]
  • [[17. Как обеспечить отказоустойчивость микросервисов]]
  • [[18. Что такое паттерн Bulkhead]]
  • [[19. Что такое паттерн Retry и как его правильно использовать]]
  • [[15. Как организовать коммуникацию между микросервисами]]