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: вмикайте СВ/політики деградації спочатку для 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 навіть в пікові та аварійні періоди.