Circuit Breaker и деградация
Circuit Breaker (CB) — это защитный паттерн, который прерывает вызовы к деградировавшей зависимости, чтобы локализовать сбой и защитить апстрим-сервисы и пользователя. Деградация (graceful degradation) — сознательное упрощение функциональности при нехватке ресурсов или отказах (например, возврат кэшированных/неполных данных, отключение «дорогих» фич) без полного даунтайма.
Главная цель: сохранить SLO и пользовательский опыт за счет контролируемых отказов, вместо каскадных падений.
1) Когда применять
Зависимость нестабильна: рост p95/p99, таймауты, ошибочные ответы.
Внешние API с жесткими лимитами/пеналти.
«Тяжелые» бэкенды (поиск, рекомендации, отчеты), где ретраи усиливают шторм.
Высоконагруженные участки с риском истощения пулов (соединения, треды).
2) Состояния CB и переходы
Классическая тройка:1. Closed — трафик идет, метрики ошибок/латентности считаются.
2. Open — вызовы мгновенно отклоняются (fail-fast) и/или переводятся на fallback.
3. Half-Open — ограниченное число «пробных» запросов определяет, закрывать ли выключатель.
Триггеры открытия
Порог ошибок/таймаутов за окно (например, ≥ 50% из N последних).
Порог латентности (например, p95 > целевого значения).
Комбинированные политики (ошибки ∧ превышение таймаута).
Время удержания (cool-down)
Фиксированное (например, 10–60 сек) или адаптивное (экспоненциальное увеличение при повторных срабатываниях).
3) Таймауты, ретраи и джиттер
Таймауты всегда короче SLO апстрима и согласованы по цепочке (deadline propagation).
Ретраи только для идемпотентных операций; 1–2 попытки достаточно в большинстве случаев.
Backoff + джиттер (full jitter) предотвращает синхронные волны повторов.
Hedging (запасные запросы) — экономно и только для очень критичных чтений.
4) Bulkhead-изоляция и «предохранители»
Разделяйте пулы соединений/воркеров/очередей по доменам и типам трафика (VIP, фоновые задачи, публичные API).
Caps на concurrency для «дорогих» операций.
Admission control: легкий отказ до выполнения при переполнении очереди.
5) Fallback и сценарии деградации
Варианты
Кэш/стейл-ответы: `stale-while-revalidate`, возврат данных из L2/L3 кэша.
Read-only: блок писать/команд, разрешить безопасные чтения.
Суррогатные ответы: неполные данные (например, без рекомендаций/аватаров).
Функциональное отключение: временно скрыть не-критичные виджеты/фичи.
Feature flags: быстрая смена поведения без релиза.
Правила
Fallback должен быть детерминированным, быстрым и безопасным по данным.
Явно помечайте деградированный путь в логах/трейсах/метриках.
6) Приоритизация и трафик-шейпинг
VIP/платные планы — больший приоритет/квоты при дефиците.
Rate limits и throttling уменьшают нагрузку на деградировавшие зависимости.
Shed load: мягкое снижение качества (например, меньше результатов, урезанные изображения) до стабилизации.
7) Наблюдаемость и сигналинг
Метрики CB
Состояние (closed/open/half-open) и длительность в состоянии.
Доля отказов по причинам: CB-open, timeout, 5xx, retry-exhausted.
p95/p99 латентность «до» и «после» выключателя.
Кол-во/доля запросов через fallback.
Трейсинг
Аннотации спанов: `circuit=opened`, `fallback=cache`, `admission=denied`.
Корреляция с лимитами (429/RateLimit-), очередями и пулями соединений.
Логи/аудит
Причина открытия/закрытия, пороги, идентификаторы зависимостей.
8) Контракты и протокол
HTTP
Fail-fast: `503 Service Unavailable` с `Retry-After` (или `429` при лимитах).
Partial content/стейл: `200`/`206` с метаданными деградации (например, `X-Degraded: true`).
Кэш-политики: `Cache-Control: stale-if-error, stale-while-revalidate`.
gRPC
`UNAVAILABLE`, `DEADLINE_EXCEEDED`, семантика ретраев по полисам клиента/прокси.
Deadline/timeout на контексте запроса; распространение дедлайна вниз по цепочке.
Идемпотентность
`Idempotency-Key` для POST-операций, дедупликация на границе.
9) Типовая реализация (псевдокод)
pseudo onRequest(req):
if circuit. isOpen(dep):
return fallbackOrFail(req)
with timeout(T):
try:
resp = call(dep, req)
circuit. recordSuccess(dep, latency=resp. latency)
return resp except TimeoutError or 5xx as e:
circuit. recordFailure(dep)
if circuit. shouldOpen(dep):
circuit. open(dep, coolDown=adaptive())
return fallbackOrFail(req)
Half-Open проба
pseudo onTimer():
if circuit. state(dep) == OPEN and coolDownExpired():
circuit. toHalfOpen(dep)
onRequestHalfOpen(req):
if circuit. allowTrial (dep): # e.g. 1 try: call -> success => close catch: reopen with longer coolDown else:
return fallbackOrFail(req)
10) Настройка порогов
Окно наблюдения: скользящее N секунд/запросов.
Порог ошибок: 20–50% в окне (зависит от профиля).
Порог латентности: p95 ≤ целевого SLO (например, 300–500 мс); превышение учитывается как «ошибка» для CB.
Адаптивный cool-down: 10s → 30s → 60s при повторных срабатываниях.
11) Тестирование и хаос-практики
Chaos: инъекция латентности/ошибок в зависимости, поломка DNS, drop пакетов.
Game days: запуск «открытия» выключателя на боеподобной среде, проверка fallback.
Canary: включайте CB/политики деградации сначала для 1–5% трафика.
SLO-бюджет: допускайте эксперименты, пока не исчерпан error-budget.
12) Интеграция с мульти-тенантностью
Состояние CB можно хранить per-dependency per-tenant (для шумных арендаторов) или глобально — в зависимости от профиля нагрузки.
Fallback-данные и кэши сегментируйте по `tenant_id`.
Приоритеты/квоты — согласно планам (VIP не должны страдать от поведения Starter).
13) Чек-лист перед продом
- Таймауты и дедлайны сквозные и согласованные.
- Ретраи ограничены, только для идемпотентных операций, с backoff+джиттером.
- Пороговые значения CB обоснованы данными нагрузочного теста.
- Fallback-пути существуют, быстрые и безопасные; кэш политики определены.
- Bulkhead-изоляция: раздельные пулы/очереди/лимиты.
- Метрики/трейсы/логи помечают деградации и состояния CB.
- Документация контрактов ответов (HTTP/gRPC) с примерами заголовков/кодов.
- Хаос-сценарии и game-days проходят регулярно; есть runbook.
14) Типичные ошибки
Нет таймаутов → ретраи «до упора» и каскадные падения.
Единый глобальный CB вместо избирательного (по эндпойнту/методу) — лишние отказы.
Открытый выключатель без fallback → «пустые» экраны вместо деградированного UX.
Ретраи без джиттера → синхронные бури запросов.
Долгий cool-down при кратковременных сбоях или слишком короткий при устойчивых — «флип-флоп» состояний.
Отсутствие bulkhead — истощение общих пулов и «head-of-line blocking».
15) Быстрый выбор стратегии
Чтения высокой важности: CB + кэш стейл-ответов + hedging (экономно).
Записи/платежи: строгие таймауты, минимум ретраев, idempotency keys, отсутствие «грязных» fallback.
Внешние API: CB с агрессивными порогами, адаптивный cool-down, строгий throttling.
Микросервисы с пульсирующей нагрузкой: bulkheads, caps на concurrency, приоритизация VIP.
Заключение
Circuit Breaker и управляемая деградация — это «страховка» архитектуры: они переводят хаотичные отказы в предсказуемое поведение. Четкие таймауты, ограниченные ретраи с джиттером, изолированные пулы, продуманные fallback-пути и телеметрия делают систему устойчивой к сбоям зависимостей и удерживают SLO даже в пиковые и аварийные периоды.