Circuit Breaker, Retry, Timeout: базовый набор устойчивости
Три механизма, которые защищают сервис от каскадных отказов: где ставить, как настраивать и какие ошибки избегать.
Большинство падений в распределённых системах — это не «один большой сбой», а цепочка мелких деградаций.
Базовая защита строится на трёх механизмах: timeout, retry, circuit breaker.
Проще говоря
Три механизма, которые защищают сервис от каскадных отказов: где ставить, как настраивать и какие ошибки избегать. Ниже — что именно делать на практике и где чаще всего ошибаются.
1) Timeout — всегда первым
Без timeout любой внешний вызов может «подвесить» воркер/поток.
Правила:
- отдельный timeout на connect и read,
- timeout короче SLA endpoint,
- явная отмена/прерывание запроса.
2) Retry — только на безопасных ошибках
Retry полезен при временных сбоях, но опасен без ограничений.
Нужно:
- ограничить число попыток,
- использовать exponential backoff + jitter,
- ретраить только retryable errors,
- учитывать идемпотентность операции.
3) Circuit Breaker — защита от каскада
Когда зависимый сервис деградирует, breaker временно «открывается» и прекращает новые тяжёлые попытки.
Состояния:
- closed (норма),
- open (отсекаем вызовы),
- half-open (пробуем восстановление).
4) Порядок применения
Обычно лучше так:
- timeout,
- retry (ограниченный),
- circuit breaker,
- резервный сценарий (если применимо).
5) Частые ошибки
- Бесконечные ретраи.
- Ретраи на 4xx/валидации.
- Один глобальный timeout «на всё».
- Breaker без метрик и алертов.
6) Метрики устойчивости
- доля timeout-ов,
- retry rate и retry success rate,
- breaker open rate,
- latency внешних зависимостей,
- резервный сценарий usage.
Короткая история из команды
При деградации внешнего сервиса система сначала терпела, потом падала каскадом. После нормальной связки timeout + ограниченный retry + breaker инциденты перестали распространяться на весь контур.
Вывод
Эти три механизма должны быть не «опцией в библиотеке», а частью архитектурного стандарта.
Когда они настроены осознанно, система перестаёт падать каскадом из-за одной внешней проблемы.
Практический сценарий внедрения
Если внедрять подход поэтапно, лучше идти от самого болезненного потока: выбрать один критичный user-journey, зафиксировать текущие метрики и применить изменения только на этом участке. Такой подход снижает риск и даёт быстрый доказуемый эффект для команды.
Метрики, которые важно отслеживать
- p95/p99 latency для ключевых операций,
- error rate и доля retry/резервный сценарий,
- время восстановления после сбоев,
- стоимость обработки запроса/события,
- доля регрессий после релизов.
Без метрик даже сильные архитектурные решения быстро превращаются в набор гипотез.
Что обычно идёт не так
- Команда пытается внедрить всё сразу вместо поэтапного поэтапный запуск.
- Нет владельца архитектурного решения и контроль расслаивается.
- Решение есть в документации, но не встроено в CI/CD и runbook.
- После внедрения нет регулярного review, и качество снова деградирует.
Пошаговый план на 30 дней
- Неделя 1: базовый уровень, ограничения, целевые KPI.
- Неделя 2: внедрение в одном потоке + алерты.
- Неделя 3: стабилизация, фиксы edge-cases.
- Неделя 4: масштабирование на соседние модули и обновление стандартов команды.
Термины простыми словами
- SLA/SLI/SLO — договорённость о качестве сервиса: что измеряем, какой целевой уровень и какие последствия при деградации.
- Idempotency — свойство операции давать тот же корректный результат при повторе одного и того же запроса.
- Circuit Breaker — защитный механизм, временно останавливающий вызовы в деградирующую зависимость, чтобы избежать каскадного отказа.
- Политика повторов — правила повторных попыток (когда, сколько раз и с каким backoff), чтобы не усилить сбой.
Этот блок нужен, чтобы статью можно было читать без предварительного контекста по всем терминам.
Как применять это в живом проекте
Обычно команда упирается не в идею решения, а в внедрение: кто владелец, где проверить эффект, как не сломать соседние модули. Поэтому лучше запускать изменения через один критичный поток, где есть понятная боль и измеримый результат.
Хорошая последовательность: сначала фиксируем baseline, затем внедряем минимально жизнеспособную версию решения, после чего смотрим на метрики 1–2 недели. Если эффект подтверждается, масштабируем на соседние сценарии. Если нет — откатываем без драм и пересобираем гипотезу.