Инцидент-менеджмент и postmortem
Алерт пришёл в 3:12 ночи: HighLatencyP95, p95 вырос с 120 мс до 1.4 секунд. Что дальше? Кто решает, насколько это страшно? Кто пишет пользователям? Кто откатывает релиз? Если на эти вопросы ответа нет — это не «командная работа», это толпа в чате, каждый со своим мнением, пока бизнес теряет деньги. Наблюдаемость из прошлой главы (трейсинг и алертинг) говорит тебе, что сломалось. Инцидент-менеджмент — это дисциплина как на это реагировать: кто, в каком порядке, с какой скоростью.
В малых командах на это смотрят свысока: «у нас три человека, какие роли, давайте просто починим». Работает, пока инциденты простые. Но хаос масштабируется быстрее людей, и весь арсенал (severity-матрица, таймлайн, postmortem) пригодится любой команде — для pet-проекта он даже важнее: запаса по прочности нет.
Разберём, что считать инцидентом (не каждый алерт — инцидент!), как классифицировать его по severity SEV1–SEV4, какие роли нужны и по какому таймлайну двигаться: detection → triage → mitigation → resolution → review. Отдельный блок — коммуникации. Затем самое ценное — blameless postmortem, который делает систему сильнее, а не ищет виноватого. И финал: как error budget превращает инциденты в объективные сигналы и зачем проводить учения (game day), когда всё работает.
Что считать инцидентом
Заголовок раздела «Что считать инцидентом»Не всё, что пищит, — инцидент. Различай четыре вещи:
- Алерт — сигнал системы мониторинга. Алертов много, они шумят, большинство снимаются сами. Алерт — повод посмотреть.
- Инцидент — событие, которое деградирует сервис для пользователей или грозит деградацией в ближайшем будущем. Критерий — не «страшное в логах», а влияние на пользователя: растёт p95, падает availability, теряются данные.
- Баг — дефект в коде. Баг становится инцидентом, когда доехал до продакшена и бьёт по пользователям. Баг в staging — работа в бэклоге.
- Запрос поддержки — один пользователь не может войти. Причина у него одного — тикет. Не могут войти все — SEV1.
Формулировка «деградация для пользователей» широкая: покрывает и «API лежит», и «почта задерживается на час» (для SaaS с онбордингом — инцидент, новые пользователи не активируются). И наоборот: диск на 92% — алерт warning, но ещё не инцидент, пока сервис не отдаёт 5xx.
Severity-матрица: SEV1–SEV4
Заголовок раздела «Severity-матрица: SEV1–SEV4»Классификация определяет: скорость реакции, кого будить, чем жертвовать. Одна матрица на всю команду, вывешенная на виду.
| Severity | Определение | Реакция | Пример |
|---|---|---|---|
| SEV1 | Сервис недоступен или теряются данные для всех пользователей | Немедленно, все руки, эскалация вне команды | База недоступна, API отдаёт 100% 5xx |
| SEV2 | Существенная деградация для многих: часть функций не работает, p95 вырос в разы | В течение 15–30 минут в рабочее время; дежурный вне его | Оплата падает для 20% платежей; p95 ×10 после релиза |
| SEV3 | Незначительная деградация, обходные пути есть | В рабочее время, по приоритету бэклога | Экспорт CSV работает, но медленно; degraded фича-флаг |
| SEV4 | Нет влияния на пользователей: инфраструктурный долг, аномалия без последствий | Планово | Диск заполнен на 90%, но сервис работает |
Два принципа, которые делают матрицу рабочей, а не декоративной:
- Severity присваивается по влиянию, а не по причине. Симптом «p95 вырос в 10 раз» — это SEV2, пока ты не понял, что это один фоновый воркер (SEV3), или что база вот-вот ляжет (SEV1). Severity динамический: пересматривается по мере triage.
- У каждого severity — владелец и SLA реакции. SEV1 — «кто угодно, прямо сейчас». SEV2 — дежурный on-call. SEV3/4 — тикет в бэклог. Без владельца матрица — красивая таблица.
Роли во время инцидента
Заголовок раздела «Роли во время инцидента»Классические роли — Incident Commander (IC), Communications Lead и Operations Lead. В команде из трёх человек роли раздаются по ходу — но называть их вслух обязательно, иначе все чинят и никто не координирует.
- Incident Commander (IC) — единая точка принятия решений. Не обязан чинить; его задача — держать картину: что знаем, что пробуем, что дальше. Слово IC решает споры: «деплоим фикс сразу» vs «сначала реплицируем».
- Communications (comms) — весь внешний и внутренний поток: статус в чат команды, статус-страница для пользователей, ответы поддержке. Ops не отвлекается на «а что отвечать клиенту?» — comms уже ответил по шаблону. Правило: нет подтверждённой информации — говорим «расследуем, обновление через 30 минут», а не молчим.
- Ops (operations) — собственно починка: метрики, логи, трейсы, откат, hotfix. Может быть несколько человек, но IC должен знать, кто чем занят.
Таймлайн инцидента: от детекта до ревью
Заголовок раздела «Таймлайн инцидента: от детекта до ревью»detection ──► triage ──► mitigation ──► resolution ──► review (минуты) (минуты) (часы) (часы/дни) (дни, вне паники)Detection: как узнали
Заголовок раздела «Detection: как узнали»Источники по убыванию ценности: алерт из мониторинга (лучший случай — узнали до пользователей), жалоба пользователя, заметил сам разработчик. Первым узнаёт пользователь — дырка в наблюдаемости, это отдельный action item postmortem.
Triage: оценка и решение
Заголовок раздела «Triage: оценка и решение»Первые 10–15 минут: подтвердить симптом, присвоить severity, назначить роли. Главное решение — стратегия: чинить вперёд (forward fix) или откатывать (rollback). Откат дешевле, пока схема БД обратимо совместима. Если триггер — миграция базы, откат может быть невозможен (см. главу про PostgreSQL-бэкапы) — тогда triage обязан сразу включить план восстановления данных.
Mitigation: снизить ущерб
Заголовок раздела «Mitigation: снизить ущерб»Цель mitigation — не починить, а сделать больно перестало. Набор: откат релиза, feature flag off, увеличить реплики, отключить интеграцию. Иногда — осознанная деградация: «отключаем рекомендации, остальное работает». Правило: mitigation без фикса — нормально, фикс без mitigation — рискованно. Откат дешевле элегантного hotfix в разгар инцидента.
Resolution: полное восстановление
Заголовок раздела «Resolution: полное восстановление»Сервис вернулся к базовой линии, подтверждено метриками, а не «кажется, работает». Подожди 15–30 минут стабильных графиков, потом resolved.
Review: postmortem
Заголовок раздела «Review: postmortem»Разбор идёт вне режима пожаротушения, через 3–5 рабочих дней после resolution.
Коммуникации во время инцидента
Заголовок раздела «Коммуникации во время инцидента»Набор каналов для малой команды:
- #incidents в мессенджере — единый канал, только по делу. Значимое событие — одной строкой с timestamp: «14:32 IC: подтверждён релиз 2.14.0 как триггер, откатываем». Чат станет скелетом таймлайна postmortem.
- Status page / пост для пользователей — шаблон: что наблюдаем (без внутренней кухни), влияние, следующее обновление через N минут, workaround если есть.
Три правила профессионалов: обновления по таймеру (каждые 30 минут для SEV1/2, даже «без изменений»), единый голос (пишет только comms), честность про данные (риск потери данных — сказать сразу).
Blameless postmortem
Заголовок раздела «Blameless postmortem»Цель postmortem — не «кто виноват», а «как система допустила это и что изменим, чтобы повторение стало маловероятным или дешёвым». Пока инцидент воспроизводим действиями одного человека в обычном процессе — проблема в системе.
Структура документа
Заголовок раздела «Структура документа»- Summary — что случилось, влияние, длительность. Две-три фразы без контекста.
- Severity и метрики влияния — потраченный error budget, минуты деградации, затронутые запросы.
- Timeline — по минутам: detection → triage → mitigation → resolution. Источник — #incidents-чат, метрики, логи деплоя.
- Root cause и contributing causes — отдельно! Root cause — непосредственная причина (отсутствующий индекс после миграции). Contributing — всё, что сделало инцидент возможным и дорогим: нет canary-выкатки, алерт p95 с
for: 10m, ручной откат. - Что сработало хорошо — обязательный раздел: алерт сработал, откат откатил, коммуникации шли по расписанию. Иначе разбор — самобичевание.
- Corrective actions — конкретные, с владельцем и дедлайном. Не «усилить тестирование», а «проверка миграций на sequential scan для таблиц > 1M строк в CI, владелец: Анна, до 20 числа».
# Postmortem: p95 API вырос в 10 раз после релиза 2.14.0
- Дата: 2026-09-08 | Severity: SEV2 (начат как SEV3, повышен) | Ведущий: on-call- Влияние: p95 1.4 s вместо 120 мс в течение 47 минут; ~12% запросов с таймаутом; error budget сгорел на 8% месячного. Данные не пострадали.
## Timeline (UTC+3)- 14:31 — алерт HighLatencyP95 (for: 10m) в Telegram, on-call подтвердил (14:34)- 14:40 — triage: триггер = релиз 2.14.0 (deploy 14:12). IC назначен, чат #incidents- 14:47 — mitigation: rollback на 2.13.2 через деплой-пайплайн- 15:18 — p95 вернулся к 130 мс; наблюдение за стабильностью- 15:35 — resolved, статус-страница обновлена- 16:10 — postmortem-черновик создан из лога #incidents
## Root causeМиграция 20260908_add_orders_index выполняла DDL-транзакцию (обычныйCREATE INDEX и ALTER TABLE, не CONCURRENTLY). Блокировка AccessExclusiveLockот DDL встала в очередь за долгим запросом к orders — все SELECT по ordersвстали в очередь блокировок.
## Contributing causes1. Миграции деплоятся в той же транзакции, что и код (нет отдельного флага/этапа)2. Алерт p95: for=10m — детект занял 18 минут от начала деградации3. Нет canary-выкатки: релиз ушёл на 100% инстансов сразу
## Что сработало- Алерт сработал до первых жалоб; rollback пайплайном отработал за 7 минут- Единый канал #incidents дал таймлайн без реконструкции по памяти
## Corrective actions| Действие | Тип | Владелец | Дедлайн ||---|---|---|---|| Миграции с DDL — отдельный этап деплоя, до кода | prevent | Анна | 2026-09-20 || Проверка в CI: долгие блокировки миграций на prod-анонимизированном дампе | prevent | Анна | 2026-09-27 || Выкатка: canary 5% → 30 мин наблюдения → 100% | prevent | Борис | 2026-10-04 || Алерт p95: for=10m → for=3m на burn rate ×6 | detect | Влад | 2026-09-15 || Runbook «p95 вырос после релиза» в docs/ | detect | Влад | 2026-09-12 |Заметь разделение типов действий: prevent (не дать случиться), detect (узнать раньше), mitigate (сделать дешёвым). Здоровый postmortem содержит все три — чинится не только причина, но и процесс обнаружения.
Error budget и инциденты: обратная связь
Заголовок раздела «Error budget и инциденты: обратная связь»Postmortem не живёт в вакууме — его влияние измеряется через error budget из главы про алертинг. Связка: сгорание бюджета порождает инцидент, инцидент — postmortem, postmortem — corrective actions, замедляющие трату бюджета. Два правила:
- Каждый SEV1/SEV2 обязан иметь postmortem. Считай количество разборов за квартал метрикой здоровья: много инцидентов с быстрыми review — нормально; много инцидентов без review — команда тонет.
- Corrective actions приоритизируются через стоимость бюджета. «Сгорели 8% месячного бюджета за 47 минут» — аргумент, чтобы поставить canary-выкатку выше новой фичи.
Обратная сторона: если инцидентов много, а бюджет почти не тратится — у тебя медленные недетектированные деградации. Худший случай: чини detection.
On-call ротация и учения
Заголовок раздела «On-call ротация и учения»Ротацию из прошлой главы (первичный/вторичный, эскалация) доводим до готовности двумя практиками:
Handover. Каждая смена начинается с 10 минут передачи: какие инциденты/алерты открыты, какие флаги крутили, что «дымится». Без handover — два дежурных, ничего не знающих друг о друге.
Game day (учения). Раз в квартал ломай систему намеренно и проверяй процесс целиком: пришёл ли алерт, взял ли его дежурный за 5 минут, сработала ли эскалация, нашёлся ли runbook. Варианты поломок: убить контейнер, заполнить диск, «потерять» подсеть до базы, просрочить сертификат (на staging!). Метрики: time-to-detect/ack/mitigate — процесс деградирует незаметно, пока его не измеряют.
#!/usr/bin/env bash# game-day.sh — учебный инцидент «приложение недоступно» (на staging!)# Запуск из cron в нерабочее время учения, чтобы логика была максимально боевой.
TARGET="staging-app-01"LOG=/var/log/game-day.log
echo "$(date -Is) GAME DAY: stopping app on $TARGET" >> "$LOG"ssh deploy@"$TARGET" "docker stop pet-api"
# Автопроверка процесса: алерт InstanceDown должен прийти за <= 2 минут,# дежурный должен подтвердить (ack) за <= 5 минут. Фиксируем факт в лог.
sleep 1800 # 30 минут на отработку инцидента командойssh deploy@"$TARGET" "docker start pet-api"echo "$(date -Is) GAME DAY: restored" >> "$LOG"Учения — по расписанию, с предупреждением руководства, но без предупреждения дежурного — иначе это театр, а не проверка ротации. После — мини-postmortem на 15 минут: что сработало, что нет, один action item.
Типичные ошибки и грабли
Заголовок раздела «Типичные ошибки и грабли»- Нет откатного плана до релиза. Плохо: «откатим как-нибудь, если что». Хорошо: перед каждым деплоем в runbook релиза одна строка: «rollback:
deploy.sh 2.13.2, миграция необратима? да/нет». Если откат невозможен — это известно ДО инцидента, и mitigation планируется заранее. - Severity навсегда. Плохо: triage присвоил SEV3 и не пересматривает, хотя симптомы растут. Хорошо: severity — живой ярлык, IC пересматривает его каждые 15–30 минут; повышение до SEV1 объявляется явно, со сменой режима работы.
- IC, который чинит. Плохо: командующий ушёл в дебаг, решения не принимаются, роль фактически пустует. Хорошо: IC говорит больше, чем печатает; если начал «проверить один момент» — передаёт командование вслух другому.
- Молчание перед пользователями. Плохо: «пока не разберёмся — писать нечего», статус-страница пустует 2 часа. Хорошо: обновление по таймеру каждые 30 минут, включая «расследуем, нового нет»; молчание читается как «нам плевать».
- Postmortem без contributing causes. Плохо: «root cause: отсутствовал индекс. Закрыто». Через месяц тот же инцидент с другим запросом. Хорошо: минимум два-три contributing cause с действиями; «что сработало хорошо» — обязательный раздел, без него команда учится на негативе и скрывает инциденты.
- «Виноват человек» как вывод. Плохо: «Иван забыл индекс, проведём беседу». Иван уволится, система останется такой, что забытый индекс доезжает до прода. Хорошо: blameless-рамка — «почему review/CI/выкатка не поймали это до прода», действия против системы, а не человека.
- Учения ради галочки. Плохо: game day, о котором знает дежурный заранее — он всё сделает идеально, процесс не проверен. Хорошо: учение внезапно для дежурного (но анонсировано руководству), замеры time-to-detect/ack/mitigate, один реальный action item после.
Вопросы на собеседовании
Заголовок раздела «Вопросы на собеседовании»- Чем инцидент отличается от алерта и от бага? Алерт — сигнал мониторинга, сам по себе не инцидент. Баг — дефект кода, инцидент — баг (или иная причина), повлиявший на пользователей в продакшене. Критерий инцидента — деградация сервиса для пользователей, а не страшность записи в логах.
- Как определяется severity инцидента? По влиянию на пользователей: SEV1 — недоступность/потеря данных для всех, SEV2 — существенная деградация для многих, SEV3 — незначительная с обходными путями, SEV4 — без влияния. Severity присваивается по симптому, динамически пересматривается по ходу triage и определяет скорость реакции.
- Зачем нужна роль Incident Commander, если все и так решают проблему? Без единой точки решений параллельные действия конфликтуют: один откатывает, другой катит фикс. IC держит картину, распределяет людей, разрешает споры и защищает ops от отвлечений. IC не чинит сам — командование и починка разделены намеренно.
- Чем mitigation отличается от resolution? Mitigation — снижение ущерба: откат, feature flag off, отключение интеграции. Resolution — полное восстановление до базовой линии. Цель mitigation — перестать терять бюджет и пользователей, а не найти идеальный фикс в разгар инцидента.
- Что такое blameless postmortem и почему он работает? Разбор без персональных претензий: фокус на системных причинах (почему процесс допустил ошибку до прода), а не на том, кто нажал кнопку. При жёсткой персональной ответственности люди скрывают инциденты, а скрытые инциденты не разбираются и повторяются. Blameless не отменяет обязательность corrective actions.
- Какие разделы должен содержать postmortem? Summary, severity и метрики влияния (сгоревший error budget), timeline, root cause и отдельно contributing causes, «что сработало хорошо», corrective actions с владельцами и дедлайнами. Типы действий: prevent, detect, mitigate.
- Зачем проводить game day, если инцидентов и так хватает? Реальные инциденты проверяют только то, что сломалось. Game day проверяет процесс целиком в контролируемых условиях: алерты, эскалацию, runbook’и, скорость реакции. Метрики учений показывают деградацию процесса до того, как она дорого обойдётся.
- Как error budget связан с инцидентами? SEV1/SEV2 — по определению быстрое сгорание бюджета. Отсюда правила: каждый SEV1/SEV2 требует postmortem, corrective actions приоритизируются через стоимость сгоревшего бюджета. Если инциденты есть, а бюджет не тратится — проблема в detection.
Практика
Заголовок раздела «Практика»Мини-проект: полный цикл инцидент-менеджмента на вымышленном, но реалистичном кейсе «p95 вырос в 10 раз после релиза». Сохрани артефакты в репозитории pet-проекта: docs/incidents/2026-09-08-p95-regression/.
- Severity и роли (30 минут). Ситуация: релиз 2.14.0 в 14:12, в 14:21 p95 вырос с 120 мс до 1.4 с, часть запросов падает по таймауту. Присвой severity по матрице и обоснуй. Назначь роли из трёх человек (ты + два коллеги), обоснуй выбор IC.
- Таймлайн. Адаптируй заготовку из главы: detection, triage с решением «откат vs фикс вперёд» (обоснуй), mitigation, resolution, review. Запись: время, событие, источник.
- Коммуникации. Напиши три обновления статус-страницы: «investigating», «identified», «resolved». Отдельно — 8 строк условного чата #incidents: строка = значимое событие с timestamp.
- Postmortem. Заполни шаблон: правдоподобный root cause (с миграцией БД), минимум три contributing causes, раздел «что сработало хорошо». Влияние посчитай честно: 47 минут деградации, твой реальный RPS, месячный error budget — сколько процентов сгорело (формула — в главе про алертинг)?
- Corrective actions. Таблица минимум из пяти действий по типам prevent, detect, mitigate. Каждое — с владельцем, дедлайном и измеримым критерием. «Добавить мониторинг» не принимается; «алерт на lock waits > 50 за 2 минуты, for: 1m» — принимается.
- Учение. Сымитируй инцидент на pet-проекте (секундная задержка в hot-эндпоинте и выкат), зафиксируй фактами: time-to-detect, time-to-ack, time-to-mitigate. Целевые: ≤ 5 / ≤ 5 / ≤ 15 минут. Один action item, если не попал.
Критерии результата: в docs/incidents/ четыре файла (severity-матрица, таймлайн + обновления, postmortem, corrective actions); postmortem содержит все разделы; у каждого action item есть владелец и дедлайн; цифры влияния посчитаны из реальных метрик.
Что почитать
Заголовок раздела «Что почитать»- Google SRE Book — Postmortem Culture: Learning from Failure — канон blameless-культуры
- PagerDuty — Postmortem Documentation и Incident Response Documentation — шаблоны и роли
- Atlassian — Incident Management Handbook — severity-матрицы и коммуникации
- Google SRE Workbook — Postmortem Toolbox — практика разборов
- AWS Well-Architected — Operational Excellence — game day и runbook-практики