Game day: отказ, диагностика, восстановление и postmortem

↑ Fullstack-практика

Желательно~8 мин чтенияУровень: middle+

Зачем это на собесе

Game day — финальная проверка всей системы: вы отрабатываете реакцию на реальные отказы, а не только «пишете код». Отличный материал для историй STAR.

Цель

Провести контролируемое учение (game day) для проекта Clinic: внести отказ, зафиксировать симптомы, диагностировать по наблюдаемости, восстановить сервис, проверить RPO/RTO и оформить blameless postmortem с задачами на улучшение.

Подготовка

  1. Цели и гипотезы: «потеря одного пода API не влияет на SLO», «падение Redis не ломает запись (деградация без кэша)», «failover PostgreSQL ≤ 60 с, потеря данных 0».
  2. Steady state — метрики нормы: доля 5xx < 0.1%, p95 < 500 мс, записи создаются, очередь outbox пуста.
  3. Роли: руководитель (incident commander), «хаос-оператор», наблюдатели/scribe, дежурные (on-call: те, кто реагирует «вслепую»), коммуникации.
  4. Безопасность: окружение (staging под синтетической нагрузкой; в проде — малый радиус и окно), условия остановки (аварийный откат, если SLO-burn выше порога), согласование и уведомление.
  5. Готовность наблюдаемости: дашборды, алерты, runbook’и, доступы (kubectl, Grafana, VPN) проверены.
  6. План и сценарий (таймлайн), канал инцидента, шаблон протокола.

Сценарии

#ОтказКак внестиОжиданиеПроверяем
1Падение подов APIkubectl delete pod -l app=api (один/несколько)трафик без потерь, rolling recoveryреплики, PDB, readiness, graceful shutdown
2Отказ ноды/зоныkubectl drain/остановка ВМподы пересоздаются в других зонахanti-affinity, запас ёмкости, PV
3Недоступен Redisостановить сервис/NetworkPolicyзапись работает (деградация), рост нагрузки на БДcache-aside, таймауты, circuit breaker
4Деградация БДзадержка сети NetworkChaos/блокировка таблицырост латентности, алерты, защита пуломтаймауты, ретраи, bulkhead, алерты
5Failover PostgreSQLостановить primaryпереключение на реплику ≤ 60 сPatroni/operator, строка подключения, ретраи приложения, RPO
6Потеря данных (ошибочный DELETE/DROP)удалить записи в stagingвосстановление из бэкапа/PITRRPO/RTO, runbook, журнал аудита
7Недоступен Keycloakостановить podуже вошедшие работают, новые входы — неткэш JWKS, время жизни токенов, сообщения пользователю
8Недоступен провайдер уведомленийблокировать egressочередь растёт, записи создаютсяoutbox, ретраи с backoff, DLQ, алерт по лагу
9Истёк сертификатподложить истёкший/ отозватьалерт за 14 дней, автоматическое продлениемониторинг сертификатов, cert-manager
10Плохой релизвыкатить версию с ошибкой (5xx/утечка)автооткат/ручной откатcanary-анализ, --atomic, откат, аннотации
11Нехватка диска/ресурсовзаполнить том/нагрузка CPUалерт, автомасштабирование/очисткапрогноз диска, HPA, лимиты
12Шторм нагрузкиk6 spikerate limiting, автомасштабирование, деградациязащита от перегрузки, SLO

Начинайте с простых (1, 3), усложняйте (5, 6), комбинируйте отказы; сценарий «слепой» для on-call (он не знает, что ломается).

Проведение

  1. Старт: подтвердить steady state, объявить начало (канал, время), запустить нагрузку (k6) для реалистичности.
  2. Внесение отказа (по таймлайну), засечь t0.
  3. Реакция: дежурный получает алерт (ждём MTTD), подтверждает (MTTA), открывает инцидент, оценивает влияние, смягчает (откат, переключение, масштабирование), коммуницирует (внутренне/статус-страница).
  4. Диагностика: метрики → логи → трассы; гипотезы; запись в таймлайн.
  5. Восстановление: критерии (метрики вернулись в норму, записи создаются), засечь MTTR; проверка целостности данных (нет потерь/дублей).
  6. Завершение: остановить нагрузку, снять эксперимент, убедиться, что система в норме.

Во время игры scribe ведёт таймлайн (UTC): что заметили, что решили, какие команды выполнили, какие алерты сработали/нет.

Что измеряем

МетрикаЗначение
MTTDот отказа до алерта/обнаружения
MTTAдо начала работы дежурного
MTTRдо восстановления
Влияниедоля ошибок, длительность деградации, расход error budget
Потеря данных (RPO факт)потерянные/дублированные записи
Качествосработали ли нужные алерты; были ли лишние; полнота runbook’ов; доступы
Коммуникациисвоевременность, ясность

Blameless postmortem

Шаблон документа:

# Postmortem: Failover PostgreSQL на staging (game day 2026-10-15)
 
**Статус:** завершён · **Серьёзность:** учебная SEV2 · **Автор:** … · **Участники:** …
 
## Резюме
Что произошло, влияние (длительность, доля ошибок, потери), итог.
 
## Влияние
- Длительность: 4 мин 20 с; ошибки API до 38%; данные: потерь нет (RPO 0), 2 дубля уведомлений.
 
## Таймлайн (UTC)
12:00:00 — остановлен primary. 12:00:18 — первый алерт HighErrorRate. 12:01:05 — дежурный подтвердил. 12:02:10 — выявлена причина (primary недоступен) …
12:04:20 — Patroni промоутил реплику; приложение переподключилось.
 
## Корневые и способствующие причины
- Строка подключения указывала на конкретный хост, а не на сервис/VIP → ручная перенастройка.
- Пул соединений не сбрасывал «мёртвые» соединения → хвост ошибок 60 с.
- Алерт по репликации отсутствовал.
 
## Что сработало хорошо / что нет
…
 
## Метрики
MTTD 18 с · MTTA 65 с · MTTR 4 мин 20 с · потрачено 6% бюджета ошибок.
 
## Действия (action items)
| # | Действие | Тип | Владелец | Срок | Статус |
| 1 | Подключаться через сервис `postgres-rw` (HAProxy/оператор) | предотвращение | backend | 2 нед | todo |
| 2 | `Connection Lifetime`/retry policy для Npgsql | смягчение | backend | 1 нед | todo |
| 3 | Алерт на лаг репликации и смену лидера | обнаружение | ops | 1 нед | todo |
| 4 | Обновить runbook «PostgreSQL недоступна» | процесс | ops | 1 нед | todo |
 
## Уроки
…

Принципы: без поиска виноватых, системные причины (5 почему), конкретные action items с владельцами и сроками, трекинг выполнения, повторное учение для проверки исправлений.

Типичные находки game day

  • отсутствие таймаутов и ретраев → подвисшие запросы и каскад;
  • readiness проверяет не то (приложение «готово», но без БД);
  • алерты слишком поздние или шумные; нет связи с runbook;
  • соединения с БД не восстанавливаются после failover;
  • нет деградации при недоступности зависимости;
  • устаревший runbook, отсутствие доступов у дежурных, неизвестные контакты;
  • бэкап есть, а восстановление не проверялось / медленнее RTO;
  • PDB/anti-affinity блокируют обновления или не защищают;
  • конфликты слотов растут при деградации БД (повторные запросы, отсутствие идемпотентности);
  • нет аннотаций релизов → непонятна причина.

Что делаем

  • Сформулировать гипотезы и steady state, выбрать 4–6 сценариев (включая failover БД и восстановление из бэкапа);
  • Подготовить окружение, нагрузку (k6), условия остановки, роли и шаблоны;
  • Провести game day, вести таймлайн, собрать метрики MTTD/MTTA/MTTR и влияние;
  • Выполнить восстановление из бэкапа и зафиксировать фактические RPO/RTO;
  • Написать blameless postmortem с action items (владельцы, сроки);
  • Исправить найденные проблемы (таймауты, ретраи, алерты, runbook’и) и повторить сценарии;
  • Автоматизировать часть экспериментов (Chaos Mesh/Litmus) и включить в регулярный процесс.

Результат / артефакты

  • план game day, таймлайн, протокол наблюдений;
  • postmortem-документ(ы), реестр action items и их выполнение;
  • обновлённые runbook’и, алерты, конфигурация (таймауты/ретраи/PDB);
  • отчёт по RPO/RTO и результатам восстановления;
  • автоматизированные chaos-эксперименты (манифесты) в репозитории.

Что рассказать на собесе

  • историю STAR: «на game day отключили primary PostgreSQL → алерт через 18 с → переключение заняло 4 мин из-за хардкода хоста и отсутствия сброса соединений → исправили, повторили: 40 с, без ошибок»;
  • как проектировали эксперименты (гипотеза, steady state, blast radius, условия остановки);
  • что нашли и как исправили, как измерили эффект (MTTD/MTTR, RPO/RTO);
  • как устроена блеймлесс-культура и отслеживание action items;
  • как game days связаны с SLO, on-call и улучшением надёжности продукта.