Game day: отказ, диагностика, восстановление и postmortem
Зачем это на собесе
Game day — финальная проверка всей системы: вы отрабатываете реакцию на реальные отказы, а не только «пишете код». Отличный материал для историй STAR.
Цель
Провести контролируемое учение (game day) для проекта Clinic: внести отказ, зафиксировать симптомы, диагностировать по наблюдаемости, восстановить сервис, проверить RPO/RTO и оформить blameless postmortem с задачами на улучшение.
Подготовка
- Цели и гипотезы: «потеря одного пода API не влияет на SLO», «падение Redis не ломает запись (деградация без кэша)», «failover PostgreSQL ≤ 60 с, потеря данных 0».
- Steady state — метрики нормы: доля 5xx < 0.1%, p95 < 500 мс, записи создаются, очередь outbox пуста.
- Роли: руководитель (incident commander), «хаос-оператор», наблюдатели/scribe, дежурные (on-call: те, кто реагирует «вслепую»), коммуникации.
- Безопасность: окружение (staging под синтетической нагрузкой; в проде — малый радиус и окно), условия остановки (аварийный откат, если SLO-burn выше порога), согласование и уведомление.
- Готовность наблюдаемости: дашборды, алерты, runbook’и, доступы (kubectl, Grafana, VPN) проверены.
- План и сценарий (таймлайн), канал инцидента, шаблон протокола.
Сценарии
| # | Отказ | Как внести | Ожидание | Проверяем |
|---|---|---|---|---|
| 1 | Падение подов API | kubectl 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, алерты |
| 5 | Failover PostgreSQL | остановить primary | переключение на реплику ≤ 60 с | Patroni/operator, строка подключения, ретраи приложения, RPO |
| 6 | Потеря данных (ошибочный DELETE/DROP) | удалить записи в staging | восстановление из бэкапа/PITR | RPO/RTO, runbook, журнал аудита |
| 7 | Недоступен Keycloak | остановить pod | уже вошедшие работают, новые входы — нет | кэш JWKS, время жизни токенов, сообщения пользователю |
| 8 | Недоступен провайдер уведомлений | блокировать egress | очередь растёт, записи создаются | outbox, ретраи с backoff, DLQ, алерт по лагу |
| 9 | Истёк сертификат | подложить истёкший/ отозвать | алерт за 14 дней, автоматическое продление | мониторинг сертификатов, cert-manager |
| 10 | Плохой релиз | выкатить версию с ошибкой (5xx/утечка) | автооткат/ручной откат | canary-анализ, --atomic, откат, аннотации |
| 11 | Нехватка диска/ресурсов | заполнить том/нагрузка CPU | алерт, автомасштабирование/очистка | прогноз диска, HPA, лимиты |
| 12 | Шторм нагрузки | k6 spike | rate limiting, автомасштабирование, деградация | защита от перегрузки, SLO |
Начинайте с простых (1, 3), усложняйте (5, 6), комбинируйте отказы; сценарий «слепой» для on-call (он не знает, что ломается).
Проведение
- Старт: подтвердить steady state, объявить начало (канал, время), запустить нагрузку (k6) для реалистичности.
- Внесение отказа (по таймлайну), засечь
t0. - Реакция: дежурный получает алерт (ждём MTTD), подтверждает (MTTA), открывает инцидент, оценивает влияние, смягчает (откат, переключение, масштабирование), коммуницирует (внутренне/статус-страница).
- Диагностика: метрики → логи → трассы; гипотезы; запись в таймлайн.
- Восстановление: критерии (метрики вернулись в норму, записи создаются), засечь MTTR; проверка целостности данных (нет потерь/дублей).
- Завершение: остановить нагрузку, снять эксперимент, убедиться, что система в норме.
Во время игры 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 и улучшением надёжности продукта.