Circuit breaker, bulkhead, fallback

↑ 7.3 Надёжность и отказоустойчивость · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Паттерны изоляции сбоев: «что будет с вашим сервисом, если зависимость упала?»

Объяснение

Circuit breaker — предохранитель вокруг вызова зависимости.

stateDiagram-v2
  [*] --> Closed
  Closed --> Open: доля ошибок выше порога
  Open --> HalfOpen: прошёл break duration
  HalfOpen --> Closed: пробные вызовы успешны
  HalfOpen --> Open: пробный вызов упал
СостояниеПоведение
Closedвызовы проходят, ошибки считаются
Openвызовы сразу отклоняются без обращения к сервису
Half-openпропускаются пробные вызовы для проверки восстановления

Bulkhead (переборка) — отдельные пулы ресурсов для разных зависимостей/клиентов: сбой или медленная зависимость исчерпает только свой лимит параллелизма (SemaphoreSlim, ConcurrencyLimiter), а не все потоки.

Fallback — запасной результат: закэшированное значение, значение по умолчанию, упрощённая функциональность, очередь на повтор, понятная ошибка.

try { return await pricing.GetAsync(id, ct); }
catch (BrokenCircuitException) { return await cache.GetStaleAsync(id) ?? Price.Unknown; }   // деградация вместо отказа

Дополнительно: timeout, load shedding (осознанный отказ части запросов при перегрузке), health-based routing.

Нюансы и подводные камни

  • Порог breaker нужно подбирать по трафику: при малом числе запросов срабатывает ложно (MinimumThroughput).
  • Fallback тоже может упасть или скрыть проблему: метрики и алерты на срабатывания.
  • Открытый breaker при пиковой нагрузке отдаёт ошибки быстро — это норма, но нужен мониторинг.
  • Bulkhead без лимитов очереди даёт бесконечное ожидание.
  • Состояние breaker локально для инстанса.

Практика

  1. Обёрните внешний вызов в circuit breaker и сымитируйте падение сервиса.
  2. Реализуйте fallback с устаревшим значением из кэша.
  3. Изолируйте два клиента разными пулами (bulkhead).

Вопросы с ответами

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