Архитектура бэкенда
Собираем воедино: собери устойчивый backend-сервис
Читать про каскад — не то же, что собрать сервис, который его переживает. Подними небольшой платёжный сервис, сводящий все семь механизмов на один код-путь, затем инжектируй ровно те сбои из этого юнита — медленный downstream, retry storm, деплой посреди нагрузки — и докажи числами, что он деградирует плавно, а не схлопывается.
Преврати модель юнита в работающую систему: скомпонуй pooling, идемпотентные retry, circuit breaker, graceful shutdown и edge load shedding в один сервис, инструментируй швы и покажи под load-тестом с инъекцией сбоев, что он гнётся, а не ломается.
Собери небольшой сервис POST /charge (Go, JVM или Node), который стоит перед нестабильным downstream-«платёжным провайдером» и базой, сочетая ограниченный pool, идемпотентные retry, circuit breaker, graceful shutdown и edge load shedding — и докажи под load-тестом с инъекцией сбоев, что он держит goodput высоким и не теряет данные, а не каскадирует в коллапс.
- Под инъекцией медленного провайдера p99 несвязанных запросов остаётся ограниченным, и pool не входит в deadlock: acquire timeout срабатывает, breaker открывается — это показано в метриках, а не утверждено.
- Под нагрузкой сверх насыщения шеддер возвращает быстрые 503, и goodput (запросы, завершённые в дедлайн) остаётся высоким, а сервис никогда не падает до нуля — продемонстрировано таблицей before/after по goodput, p99 и доле 503.
- Тест retry storm показывает, что ограниченные retry плюс breaker предотвращают метастабильный коллапс: когда провайдер восстанавливается, сервис восстанавливается сам без ручного bounce.
- SIGTERM во время устойчивой нагрузки теряет ноль in-flight charge (таблица идемпотентности не показывает ни дубликатов, ни потерянных записей), и drain укладывается в grace period, с логированной drain duration.
- Короткое описание, называющее для каждого требования, какой механизм закрыл какой failure mode, и какие гейты ты осознанно оставил приоткрытыми с учётом blast radius сервиса.
- Добавь одностраничный on-call runbook: триаж по дашбордам RED + saturation + breaker, порядок интервенции для метастабильного каскада (сбросить, ограничить retry, сбросить breaker) и чек-лист верификации.
- Добавь второй downstream и bulkhead, чтобы сбой одной зависимости не мог поглотить весь pool — покажи, что исчерпание одного bulkhead оставляет другой эндпоинт здоровым.
- Определи SLO и error budget для /charge, посчитай burn бюджета из метрик load-теста и подключи алерт, который гейтил бы выпуск фич, когда бюджет почти истрачен.
- Прогони полный readiness-чек-лист из урока 06 по своему сервису, оцени каждый из восьми гейтов и задокументируй калибровку по blast radius с явными, честными оговорками.
Это та система, к которой вёл весь трек: один сервис, где pool, идемпотентные retry, breaker, graceful shutdown, шеддер и observability действуют на одном запросе под одной нагрузкой. Собрать её один раз — и увидеть, как твоя собственная инъекция сбоев гонит её к каскаду, а механизмы держат goodput, не теряют данных и сами восстанавливаются — превращает модель юнита в то, за чем можно стоять, когда реальный сервис вот-вот примет трафик, и сказать: да, и вот откуда я это знаю.