Архитектура бэкенда
Circuit breakers: сдержи каскадный сбой
Читать про каскадные сбои — не то же, что вытаскивать сервис из одного. Построй небольшой сервис с тремя downstream’ами, замедли наименее важный, пока весь сервис не упадёт, затем добавляй инструменты юнита по одному — timeout, breaker, bulkhead, fallback — и докажи числами, что один больной downstream больше не может уронить всё.
Преврати ментальную модель юнита в воспроизводимый инженерный цикл: воспроизведи каскад от медленной зависимости, затем послойно добавь fast-fail, изоляцию и деградацию, пока blast radius не будет сдержан — проверяя каждую защиту измерениями до/после под идентичной нагрузкой.
Построй сервис, который зовёт три downstream'а из общего пула воркеров, доведи его до каскадного сбоя, замедлив наименее критичный, затем добавь timeout, circuit breaker, bulkhead и fallback, пока эта медленная зависимость не перестанет голодить критичные маршруты — доказывая каждый шаг измерениями, а не утверждениями.
- Таблица до/после: p99 задержки и error rate на маршрут плюс насыщение пула, измеренные под одной и той же нагрузкой с инжектированным сбоем — а не оценённые.
- Логи или трасса состояний, показывающие breaker, переходящий closed в open на инжектированном сбое, ждущий cooldown, зондирующий в half-open ограниченным числом пробных вызовов и возвращающийся в closed после снятия сбоя.
- Со всеми защитами критичные маршруты (платежи, поиск) держатся в SLO, пока рекомендации замедлены весь тест — каскад сдержан в одном отсеке.
- Абзац-разбор: какая защита остановила какой сбой — timeout превращает зависание в считаемый отказ, breaker быстро отказывает, bulkhead изолирует бюджет, fallback решает, что вернуть.
- Добавь слой retries под breaker'ом и воспроизведи retry storm, затем покажи, что exponential backoff с jitter плюс абсолютный бюджет ретраев на процесс (например, 60/мин) и держание breaker'а над ретраями ограничивает амплификацию.
- Масштабируй до нескольких инстансов за балансировщиком и понаблюдай пер-инстансовое состояние breaker'а — покажи один сработавший инстанс, пока другой продолжает звать, затем добавь jitter в тайминг half-open пробы и продемонстрируй, что пробы больше не сбиваются в стадо.
- Добавь одностраничный on-call runbook: как читать четыре панели, как отличить каскад от сбоя одной зависимости, порядок применения защит и чек-лист верификации.
- Добавь координированный priority-based load shedding с deadline-aware очередью и покажи, что под перегрузкой всего сервиса флот стабильно сбрасывает низкоприоритетный трафик вместо перемешивания нагрузки между инстансами.
Это цикл, который ты будешь запускать в каждом реальном инциденте устойчивости: воспроизведи каскад, чтобы увидеть его, затем добавляй защиты по порядку и доказывай каждую числами — timeout превращает зависание в считаемый отказ, breaker быстро отказывает больной зависимости, bulkhead изолирует её бюджет, чтобы она не голодила критичные маршруты, а fallback решает, что вернёт вызывающий, когда breaker открыт. Сделав это раз на игрушечном сервисе с измерениями до/после под идентичной нагрузкой, ты доводишь production-версию до мышечной памяти — а stretch-цели уносят это во флот, где у retries, сбивающихся в стадо проб и shedding’а свои ответы.