Модуль 8. «Чёрная пятница»: несколько отказов одновременно
Цель модуля: пройти комбинированный инцидент — когда одновременно деградируют база, реплика и внешняя зависимость — и научиться действовать по регламенту: зафиксировать влияние, локализовать слои, приоритизировать, восстановить и написать постмортем без поиска виноватых.
Перед началом: модули 1, 2 и 7 (индекс и пул, лаг реплики, отказ партнёра). Инструменты: стенд
polygon/, Grafana, psql,make. Трудоёмкость: ~2–3 ч (инцидент 40 мин · разбор 40 мин · постмортем 40 мин).
🔥 Инцидент: «всё сломалось одновременно»
Распродажа, 12:00. За первые пять минут приходят три сигнала:
- p99 листинга заказов вырос с 0.2 с до ~4 с, в логах api — таймауты чтения.
- Поддержка: «клиент оплатил, а заказ не появился в списке».
- p99 вызовов партнёра (проверка риска) — секунды, часть запросов висит.
Выкаток не было. В базе — уборка индексов, на реплике — «плановое обслуживание» с паузой replay, у партнёра — деградация на их стороне. По отдельности каждый отказ знаком по модулям 1, 2 и 7; вместе они дают картину «лёг весь сервис», в которой легко запаниковать и начать чинить не то.
Задача модуля — не выучить новый паттерн, а отработать порядок действий: сначала влияние и масштаб, потом слои, потом причины. Один и тот же набор метрик и SQL-запросов, что в предыдущих модулях, только под давлением.
📖 8.1. Первые пять минут: влияние, а не причины
Порядок, который экономит часы:
- Что не работает для пользователя. Листинг? Создание? Оплата? Один
маршрут или все? Ответ — в Grafana (латентность и RPS по маршрутам) и в
/healthzпротив/readyz. - Когда началось. Сопоставьте рост p99 с временем изменений: деплой, миграция, обслуживание, рост трафика.
- Что изменилось. Дежурный не обязан знать про ночную уборку индексов;
он обязан спросить «что меняли за последние сутки» и посмотреть
pg_stat_activity, лаг реплики, алерты. - Масштаб. Один пользователь, один маршрут, весь сервис, вся система? Это определяет, тушить ли точечно или объявлять общий инцидент.
В комбинированном сценарии все три отказа видны на разных панелях: латентность
/orders, лаг реплики (SQL), p99 /risk и исходы вызовов партнёра. Панели не
складываются в одну причину — и это нормально: причин три.
Схема — ваш маршрут в любом инциденте: подтвердить симптом цифрой, определить
слой, проверить гипотезу инструментом, починить причину и вернуться по кругу,
пока make check-N не станет зелёным. Постмортем — не финальная галочка, а
следующий вход в цикл: найденная защита должна закрыть повторение.
📖 8.2. Приоритизация: что чинить первым
Правило простое: сначала то, что возвращает пользователю основной сценарий, и только потом то, что уменьшает шум.
| Отказ | Влияние | Что делать первым |
|---|---|---|
Нет индекса на /orders | основной сценарий, все пользователи | восстановить индекс |
| Пауза replay на реплике | часть пользователей не видит свои заказы | возобновить replay |
| Партнёр висит | вторичная проверка, деградация | включить защиты, не тушить партнёра |
Индекс и replay — причины, которые вы контролируете; партнёр — внешняя зависимость, её «чинят» защитами (bulkhead, circuit breaker, таймаут), а не перезапуском чужого сервиса. Если начать с партнёра, листинг всё равно останется медленным, и пользователи не увидят улучшения.
📖 8.3. Чек-лист дежурного
Держите его перед глазами во время инцидента:
- Подтвердить симптом цифрой (p99, доля ошибок, лаг) и время начала.
- Проверить
/healthzи/readyz: жив ли процесс, готовы ли зависимости. - Посмотреть Grafana: RPS, p99 по маршрутам, 5xx, пул, кэш, партнёр.
- Проверить БД:
pg_stat_activity, блокировки, план подозрительного запроса. - Проверить реплику:
pg_is_in_recovery(),pg_last_wal_replay_lsn(),pg_wal_lsn_diff(), состояние replay. - Проверить пайплайн (если full): лаг группы sink, лаг слота,
/stats. - Проверить зависимости:
/debug/partner, исходы вызовов. - Записать таймлайн действий — он понадобится для постмортема.
📖 8.4. Восстановление и проверка
Сценарий 8 собран из уже знакомых поломок:
bashmake fail-8 # индекс + пауза replay + партнёр без защит make check-8 # красный: каждый слой проверяется отдельно make fix-8 # индекс, replay, защиты make check-8 # зелёный: SLO вернулись
check-8 последовательно запускает check-1, check-2, check-7, а в
full-профиле ещё check-3 и check-4. Это важно: комбинированный инцидент
считается закрытым только когда зелёные все слои, а не тот, который вы
чинили последним.
Если что-то пошло не так и стенд в неопределённом состоянии — make reset
удаляет тома и возвращает исходные данные; это тоже часть регламента:
иногда быстрее пересоздать окружение, чем разбираться с накопленным мусором.
📖 8.5. Постмортем без виноватых
Хороший постмортем отвечает на вопросы «что произошло» и «что изменим», а не «кто виноват». Шаблон на одну страницу:
textИнцидент: <короткое имя> Дата/время: <начало — конец> Влияние: <кто и что не мог делать, сколько пользователей/заказов> Симптомы: <метрики и цифры на момент обнаружения> Таймлайн: <время — действие — результат> (5–10 строк) Причины: <цепочка, а не одна точка; отметьте усилители> Почему не заметили раньше: <алерты, пороги, слепые зоны> Что починили: <конкретные действия и проверки> Защита: <что добавляем, чтобы не повторилось: тест, алерт, лимит, регламент> Открытые вопросы: <что осталось неизвестным>
В нашем сценарии причины три, и это ключевой вывод: не ищите одну кнопку. Уборка индексов без проверки статистики на реплике, обслуживание с паузой replay без уведомления дежурного и отсутствие защит вокруг партнёра — три независимых решения, которые совпали по времени.
📖 8.6. Компромиссы
- Тушить всё сразу vs по приоритету. Распараллеливание помогает, но повышает риск ошибочных действий; приоритет — основной сценарий.
- Быстрое восстановление vs поиск корня. Сначала вернуть SLO (индекс, replay), потом разбираться, почему индекс удалили.
- Больше алертов vs меньше шума. Алерт на каждый симптом приводит к усталости; лучше несколько алертов на пользовательские SLO плюс дашборд.
- Blameless vs ответственность. Постмортем без виноватых не отменяет ответственности за решения — он отделяет людей от системных причин.
💻 Практика
- Подготовка (10 мин).
make up-full && make seed && make debezium. Откройте Grafana и убедитесь, что базовые панели зелёные. - Зафиксируйте норму (5 мин).
make load-reads,make load-riskпо 10–15 с; запишите p99/ordersи/risk, лаг реплики (SQL), лаг группыpayments. - Инцидент (15 мин).
make fail-8. Не смотрите скрипты — работайте как дежурный: Grafana →/readyz→pg_stat_activity→ реплика → партнёр. Записывайте таймлайн: время, что проверили, что увидели. - Проверка «сломано» (10 мин).
make check-8— красный. Разберите, на каком слое он остановился и почему. - Восстановление (10 мин).
make fix-8, затемmake check-8— зелёный. Если check-3/check-4 не проходят, проверьте, что вы в full-профиле и коннектор Debezium в состоянии RUNNING (make debezium). - Постмортем (20 мин). Напишите документ по шаблону 8.5: влияние, три причины, почему не заметили, защита. Один абзац — что бы вы сделали иначе, если бы инцидент повторился завтра.
🧩 Quiz "Проверь себя"
check-8 прогоняет проверки всех слоёв, а не только последнего фикса?✅ Итоги модуля
- Пройти комбинированный инцидент
fail-8 → check-8 (red) → fix-8 → check-8 (green). - Действовать по чек-листу дежурного, а не по памяти.
- Объяснить приоритизацию: основной сценарий раньше вторичных зависимостей.
- Написать постмортем по шаблону: влияние, таймлайн, три причины, защита.
- Назвать по одной защите для каждого из трёх отказов.
- Уметь вернуть стенд в исходное состояние через
make reset.
🎓 Финал: от стенда к проду
Полигон закончился, но регламент остался: подтвердить симптом цифрой, локализовать слой, проверить гипотезу инструментом, починить причину, оставить защиту. Эти пять шагов работают и на локальном compose, и на проде с Kubernetes — меняются только инструменты.
Что стоит сделать дальше на своём проекте:
- перенести три алерта из курса на реальные SLO (латентность, ошибки, лаг);
- добавить проверку статистики индексов на той реплике, куда идут чтения;
- завести регламент обслуживания реплик с уведомлением дежурного;
- обернуть каждую внешнюю зависимость таймаутом, bulkhead и circuit breaker;
- научиться писать постмортем на одну страницу — и писать его после каждого инцидента, даже маленького.