SRE и надёжность Реакция на инцидент: роли, связь, первые действия
0%

Реакция на инцидент: роли, связь, первые действия

Реакция на инцидент: роли, связь, первые действия

03:52. Пейджер сработал по правилу CheckoutErrorRate, и в этот раз это не ерунда: половина платежей падает. Дежурный открывает чат.

04:01 — в канале уже семь человек. Двое смотрят графики базы, один зашёл в под и перезапускает сервис, ещё один пишет в личку тимлиду, тимлид пишет в личку дежурному «что там?», кто-то спрашивает «а мы уже откатили?», ему никто не отвечает, потому что каждый думает, что ответит другой. В 04:07 в канал заходит директор и пишет «клиенты жалуются, статус?». Дежурный тратит четыре минуты на ответ директору.

04:19 — выясняется, что двое параллельно правили одну и ту же конфигурацию, и второй перезаписал изменение первого. В 04:26 кто-то наконец говорит вслух: «Ребята, а релиз в 03:40 был?». Был. 04:33 — откат. Платежи возвращаются. Сорок одна минута.

Отката хватило бы и в 03:57. Всё, что произошло между 03:57 и 04:33, — это не работа над аварией, это работа над собственной неорганизованностью. И это типичная пропорция: в разборе инцидентов почти всегда обнаруживается, что техническое действие, которое всё починило, занимало минуты, а нашли его через десятки минут — не из-за сложности системы, а из-за того, что никто не отвечал за то, чтобы его искали системно. Эта глава — про инженерную дисциплину реакции. Не про героизм и не про «оставайтесь спокойны». Разберём: что считать инцидентом и почему это должен быть порог, а не ощущение; почему толпа чинит медленнее, чем трое, и посчитаем это; какие роли нужны; как устроены первые тридцать минут; почему митигация обгоняет диагностику; когда эскалировать и сколько это стоит в деньгах; какую цену платят живые люди за то, что процесс вообще существует.

Предполагается, что вы прочли главы про SLI и SLO, бюджет ошибок, алерты и дежурство: алерт разбудил человека — на этом заканчивается предыдущая глава, что человек делает дальше — здесь. Со стороны руководителя тот же процесс разобран в главе про дежурства и инциденты трека по инженерному лидерству — там про ресурс, защиту людей и про то, как не превратить разбор в разнос. Здесь — со стороны инженера, который в 03:52 держит телефон.

Что считать инцидентом: порог, а не ощущение

Первая ошибка большинства команд — отсутствие определения. «Инцидент» объявляют, когда кому-то стало страшно, и не объявляют, когда все устали. В результате процесс срабатывает случайным образом. Рабочее определение простое и опирается на то, что вы уже посчитали:

Инцидент — это событие, которое сжигает бюджет ошибок заметной долей и требует координации нескольких человек либо отступления от обычного порядка работы.

Оба условия важны. Одиночная ошибка, которую дежурный чинит за две минуты, инцидентом не является, даже если она была неприятной. Событие, которое требует собрать трёх человек ночью, — является, даже если пользователи ещё ничего не заметили. Порог задаётся арифметикой, а не интуицией. Возьмём SLO 99,9 % доступности на календарный месяц из 30 дней:

минут в месяце      = 30 × 24 × 60 = 43 200
допустимо «плохих»  = 43 200 × (1 − 0,999) = 43,2 минуты

Сорок три минуты на месяц. Не в день — в месяц. Теперь переведём в порог объявления:

Доля бюджета Эквивалент полного отказа Уровень Что это означает
≥ 5 % ≥ 2,2 мин SEV3 объявляем, чиним в рабочем режиме
≥ 20 % ≥ 8,6 мин SEV2 будим владельца сервиса
≥ 50 % ≥ 21,6 мин SEV1 будим всех, кого надо, статус наружу

Первая реакция на такую таблицу — «да у нас тогда всё будет SEV1». Это не ошибка таблицы, это правильный вывод: при SLO 99,9 % почти любая заметная авария съедает десятки процентов месячного бюджета. Сорок три минуты — действительно мало. Если вам кажется, что уровни срабатывают слишком часто, у вас два честных выхода: снизить SLO до значения, которое вы реально держите, или признать, что аварий у вас много. Третий выход — «не объявлять инцидент, чтобы не портить статистику» — не инженерный, и о нём ниже. Частичные отказы считаются пересчётом в «эквивалент полного»:

падает 25 % запросов в течение 40 минут
эквивалент полного отказа = 40 × 0,25 = 10 минут
доля бюджета = 10 / 43,2 = 23 %  → SEV2

Это тот же приём, что и в главе про бюджет ошибок: всё сводится к одной валюте — «плохим минутам».

Объявлять должно быть дёшево. Это ключевая настройка, и она про асимметрию цен. Ложно объявленный инцидент стоит: пять минут суеты и лёгкая неловкость. Не объявленный вовремя настоящий инцидент стоит: десятки минут задержки, потому что люди подключались по одному и каждый начинал с нуля. Асимметрия — раз в десять, поэтому политика должна быть «сомневаешься — объявляй», а закрытие инцидента через десять минут с пометкой «не подтвердилось» должно считаться нормальным исходом, а не поводом для шуток. Команда, где над «ложной тревогой» смеются, через полгода получает дежурного, который в 03:52 сидит один и надеется, что само пройдёт.

Уровни серьёзности — это обязательства, а не ярлыки

Уровень серьёзности бесполезен, если он ничего не меняет. Смысл SEV не в том, чтобы обозначить, насколько всем страшно, а в том, чтобы заранее ответить на вопросы, которые в 04:00 никто не хочет обсуждать: кого можно будить, как часто писать статус, можно ли трогать данные, нужно ли уведомлять клиентов. Полезно держать это конфигом рядом с кодом, а не строчкой в вики, которую никто не открывал два года:

# incident-policy.yaml — политика инцидентов как код: лежит в репозитории,
# меняется через PR, пересматривается на ретро раз в квартал.
severity:
  SEV1:
    критерий: ">= 50% месячного бюджета ошибок или потеря/порча данных"
    будить: ["дежурный", "владелец сервиса", "дежурный руководитель"]
    роли: ["командир", "оператор", "связь", "журналист"]  # все четыре обязательны
    статус_наружу: "публичная страница + письмо ключевым клиентам"
    каденция: "каждые 30 минут, даже если ничего не изменилось"
    постмортем: "обязателен, 5 рабочих дней"
  SEV2:
    критерий: ">= 20% месячного бюджета ошибок"
    будить: ["дежурный", "владелец сервиса"]
    роли: ["командир", "оператор"]        # связь и журнал совмещает командир
    статус_наружу: "публичная страница, если длится > 15 минут"
    каденция: "каждые 30 минут"
    постмортем: "обязателен, 10 рабочих дней"
  SEV3:
    критерий: ">= 5% бюджета либо деградация без отказа"
    будить: []                            # только в рабочие часы
    роли: ["командир"]
    статус_наружу: "нет"
правила:
  повышение_уровня: "может любой участник, в одностороннем порядке"
  понижение_уровня: "только командир инцидента"
  отмена: "закрыть с пометкой «не подтвердилось» — нормальный исход, не ошибка"

Обратите внимание на асимметрию в конце: повысить уровень может кто угодно, понизить — только командир. Это защита от политического давления, при котором SEV1 через полчаса тихо становится SEV3, потому что «не хочется портить квартальные цифры». И на строку «каждые 30 минут, даже если ничего не изменилось». Отсутствие новостей воспринимается снаружи как «про нас забыли», а внутри — как повод спросить лично, что стоит времени командира. Сообщение «в 04:30 гипотеза та же, проверяем базу, следующий апдейт в 05:00» стоит тридцать секунд и снимает десяток вопросов.

Почему толпа чинит медленнее: арифметика координации

Интуиция «больше людей — быстрее» здесь ломается, и ломается количественно. Когда ролей нет, координация идёт по принципу «каждый с каждым». Число каналов связи в группе из n человек:

каналов = n × (n − 1) / 2
Людей Каналов без ролей Каналов при звезде с командиром
3 3 2
4 6 3
6 15 5
8 28 7
12 66 11

Рост числа связей — O(n²), а полезной работы — в лучшем случае O(n), и то с оговорками, потому что параллелить диагностику одной аварии почти нечем. При шести участниках это уже 15 пар, между которыми должно поддерживаться общее понимание ситуации; каждое новое наблюдение нужно донести до всех, и стоимость этого доносится в тех же минутах, что тикают в бюджете ошибок.

Полносвязная толпа против звезды с командиром инцидента

Звезда с одним командиром даёт O(n) каналов, и это единственная причина, по которой роль командира существует. Не иерархия, не «главный умный», не корпоративный ритуал — снижение степени графа связей.

Ровно это явление в терминах системного мышления выглядит как усиливающая петля: больше людей → больше вопросов → больше времени уходит на ответы → медленнее чинится → тревожнее → подключается ещё больше людей. Петля не имеет естественного ограничителя, поэтому ограничитель ставят руками: правило «в канале координации говорят только роли, остальные читают». Лора Магуайр в диссертации «Controlling the Costs of Coordination in Large-scale Distributed Software Systems» (Ohio State University, 2020) показывает на записях реальных инцидентов, что заметная доля когнитивной нагрузки дежурного уходит не на диагностику, а на решение, кого и когда подключить, и на поддержание общей картины у подключившихся. Отчёт STELLA группы SNAFUcatchers (Allspaw, Cook, Woods и др., 2017) фиксирует то же самое: инженеры в инциденте тратят существенное время на «выравнивание представлений» — и это работа, которую можно спроектировать, а можно оставить самотёком.

Роли: кто командует, кто чинит, кто говорит

Схема ролей в IT пришла не из IT. Её прообраз — Incident Command System, разработанная пожарными Калифорнии в 1970-х после сезона пожаров, где основные потери были вызваны не огнём, а несогласованностью ведомств. Позже ICS стала частью федерального стандарта NIMS. Google перенёс её в инженерию под названием IMAG и описал в главе 14 книги SRE, PagerDuty выложила свою практику открыто на response.pagerduty.com. Путь один и тот же: 1970 — пожары в Калифорнии, 1972 — FIRESCOPE и первая формализация единого командования, 1980-е — перенос в медицину катастроф и авиацию (Crew Resource Management), 2004 — ICS как федеральный стандарт, 2016 — IMAG в книге SRE. Четыре роли покрывают почти всё. Командир инцидента (IC, incident commander). Владеет процессом, не решением. Держит в голове текущее состояние, список гипотез и список действий, принимает решения при разногласиях, назначает остальные роли. Ключевое: командир не чинит. Как только он лезет в консоль, он перестаёт держать картину, и через десять минут никто не знает, что происходит. Это самая контринтуитивная часть схемы, потому что командиром обычно становится самый опытный, и именно ему больше всех хочется в консоль. Что говорит командир, дословно:

  • «Я командир инцидента» — вслух, в канал, с меткой времени. Роль захватывается, а не выдаётся.
  • «Аня, ты оператор. Проверь, был ли релиз в последние два часа. Ответь через пять минут даже если ничего не нашла».
  • «Стоп. Никто не трогает продакшн без объявления в канал. Сейчас двое правили один конфиг».
  • «Текущая гипотеза — релиз 03:40. Действие — откат. Кто против?» — пауза три секунды — «Откатываем».
  • «Мы в этой гипотезе 15 минут без прогресса. Меняем: Дима смотрит базу, Аня — сеть».

Оператор (ops lead). Единственный, кто выполняет изменения в проде во время инцидента. Не потому что остальные глупее, а потому что параллельные изменения делают систему ненаблюдаемой: когда трое одновременно что-то поправили, невозможно понять, что помогло и что сломало дополнительно. Правило «руки в проде — только у оператора, остальные предлагают команды в канал» экономит больше времени, чем любая автоматизация.

Связь (communications lead). Пишет наружу: статусная страница, письмо поддержке, ответ в клиентский чат. И — что не менее важно — служит буфером: перехватывает вопросы «ну что там?» от руководства и клиентов, чтобы они не долетали до командира. В инциденте из первого абзаца этой главы четыре минуты дежурного ушли на ответ директору. Роль связи стоит того, чтобы существовать, хотя бы ради этих четырёх минут.

Журналист (scribe). Пишет журнал с метками времени: что заметили, что решили, что сделали, что получилось. Не протокол совещания, а поток фактов. Без журнала постмортем через два дня превращается в коллективное сочинение по мотивам, а таймлайн — в реконструкцию по логам Slack, где половина решений принималась голосом.

Обратите внимание: в 04:04 вопрос снаружи получает ответ, но не от командира — это и есть работа роли связи.

Свёртка ролей в маленькой команде. Четыре роли не означают четырёх человек. Означают четыре набора обязанностей, которые кто-то держит:

Людей в инциденте Как раскладывается
1 Дежурный — всё сразу. Журнал ведётся командами в канал: пишешь, что делаешь, до того как сделал
2 Один командует и пишет наружу, второй чинит. Разделение «руки/голова» важнее всех остальных
3–4 Командир, оператор, связь. Журнал — на командире или на боте
5+ Все четыре роли отдельными людьми, остальные — в канале наблюдателей, молча

Даже в одиночку разделение полезно: правило «сначала напиши в канал, что собираешься сделать, потом делай» дисциплинирует и создаёт журнал бесплатно. Это же спасает при передаче: подключившийся в 04:20 читает канал и за две минуты понимает, что уже пробовали.

Первые тридцать минут

Разложим по минутам; числа ниже — не норматив, а ориентир. Минуты 0–2. Подтвердить. Прежде чем поднимать людей — убедиться, что проблема реальна. Проверка обязана идти с точки, независимой от подозреваемого компонента: внешняя синтетическая проба, запрос с телефона по мобильной сети, дашборд другого провайдера. Классическая потеря десяти минут — расследование аварии, которой нет: сломался экспортёр метрик, а не сервис. Про то, какие сигналы чему верят, — глава про мониторинг.

Минуты 2–4. Объявить и назвать себя командиром. Вслух, текстом, с меткой времени. Создать канал (или запустить бота). Назначить роли поимённо — «кто-нибудь посмотрите базу» не назначает никого.

Минуты 4–8. Собрать состояние. Три вопроса, которые задаются всегда и в этом порядке:

  1. Что изменилось? Релизы, миграции, флаги, конфиги, права, сертификаты, изменения у провайдера. Отраслевые оценки расходятся, но доля инцидентов, начинающихся с изменения, обычно называется в диапазоне двух третей и выше — и это единственный вопрос, ответ на который стоит искать в первую очередь всегда. Хронология деплоев на одном экране с графиком ошибок — самый дешёвый инструмент диагностики из существующих.
  2. Кто страдает? Все или часть? Один регион, один тариф, один тип клиента? Ответ сужает область поиска сильнее любых логов.
  3. Что уже пробовали? Особенно если вы подключились не первым.

Минуты 8–15. Митигировать. Не «понять». Вернуть работу. Минуты 15+. Либо стало лучше, либо меняем гипотезу. Таймбокс на гипотезу — 15 минут. Не подтвердилась — командир объявляет смену направления. Без таймбокса группа залипает в первой правдоподобной версии на час.

Два сценария первых минут инцидента

Разница между сценариями A и B на картинке — 26 минут, то есть 60 % месячного бюджета при SLO 99,9 %. Ни одна из этих минут не была потрачена на написание кода.

Митигация раньше диагностики

Это главное правило реакции, и оно противоречит инстинкту инженера. Инженера учили не трогать, пока не понял. В инциденте приоритет обратный: вернуть пользователю работу, потом разбираться. Причина не в спешке, а в арифметике: диагностика идёт под давлением, ночью, на неполных данных — то есть в худших условиях из возможных. Те же люди утром, выспавшиеся, с полными логами и без тикающего бюджета, найдут причину быстрее и вернее. Единственное, что нельзя отложить, — страдание пользователей.

Правый верхний квадрант — то, ради чего вообще существуют безопасные релизы и механизмы деградации. Флаг и откат ценны не тем, что они элегантны, а тем, что их можно применить, не понимая причину, и отменить, если не помогло. Инцидент — это ровно та ситуация, для которой их строили. Правый нижний — ловушка. Ручная правка данных в базе выглядит как быстрое решение и почти всегда необратима: если гипотеза была неверной, вы только что добавили к аварии порчу данных. Правило: любые операции с данными — только с явного решения командира, со снапшотом до и вдвоём (второй читает команду вслух перед выполнением). Левый нижний — «напишем хотфикс». Код под давлением, без ревью, без прогона тестов, в три часа ночи. Медленно и необратимо одновременно. Иногда выхода нет, но это должно быть осознанным решением командира, а не действием по умолчанию.

Каноничный публичный пример правого верхнего квадранта — отказ Cloudflare 2 июля 2019 года. Одно регулярное выражение в новом правиле WAF вызвало катастрофический бэктрекинг и съело CPU на всей глобальной сети. Инженеры не стали искать, какое именно правило виновато: в 14:02 UTC они глобально выключили весь WAF, и к 14:09 трафик вернулся. Разбор, какое правило и почему, занял потом много часов — но уже без пользователей на линии. Около 27 минут вместо нескольких часов ровно потому, что существовал глобальный рубильник и решение применить его до понимания причины. Обратный пример — отказ базы GitLab 31 января 2017 года: усталый инженер в час ночи удалил каталог данных на боевом сервере вместо реплики. Дальше выяснилось, что пять из шести механизмов резервного копирования не работали. Восстановление заняло около 18 часов, часть данных потеряна навсегда. Этот инцидент стоит прочитать целиком: GitLab вёл разбор публично, в открытом документе, в реальном времени — редкий и очень полезный материал.

Связь: канал — это протокол, а не чат

Один канал координации, один канал статуса. Координационный — рабочий, шумный, для ролей. Статусный — читают наблюдатели, руководство, поддержка; туда пишет только роль связи, по расписанию. Смешивание двух назначений в одном канале означает, что либо работа тонет в вопросах, либо наблюдатели не знают, что происходит.

Личные сообщения во время инцидента запрещены. Не из вредности: информация, ушедшая в личку, для всех остальных не существует. Подключившийся в 04:20 инженер читает канал и должен получить полную картину. Если половина решений принималась в переписке двоих, он её не получит, задаст те же вопросы заново и потратит время командира. Формулировка правила: канал — это запись, всё, чего нет в канале, не произошло.

Голос или текст. Голосовой мост быстрее для обсуждения гипотез и незаменим, когда участников больше пяти. Но он не оставляет следа и исключает тех, кто подключился позже. Рабочий компромисс: обсуждаем голосом, решения и действия дублируем текстом. Роль журналиста в голосовом инциденте становится обязательной, а не желательной.

Закольцованная связь. Приём из авиации и медицины (closed-loop communication): получатель повторяет команду вслух, исполнитель сообщает о завершении.

Плохо:  IC:  «Откати релиз»
        Ops: (молчит, делает) ... через 8 минут: «А, я думал ты про предыдущий»
Хорошо: IC:  «Аня, откати релиз checkout 03:40 до предыдущего тега. Подтверди»
        Ops: «Принято: откат checkout с v2.14.1 на v2.14.0. Выполняю»
        Ops: «Готово 04:02:40, все поды на v2.14.0»

Выглядит избыточно ровно до первого инцидента, где двое «поняли по-разному». Три лишние строки стоят десяти секунд и снимают целый класс ошибок.

Шаблон объявления. Первое сообщение в канале задаёт структуру всему остальному:

🔴 ИНЦИДЕНТ INC-2026-0731-01 · SEV2 · открыт 03:54
Симптом:      48 % запросов POST /api/checkout отвечают 500
Кто страдает: все клиенты, оплата картой; корзина и каталог работают
Начало:       03:47 по графику ошибок
Бюджет:       сожжено ~9 % месячного (SLO 99,9 %)
Роли:         командир @ivan, оператор @anna, связь @dmitry, журнал @lena
Гипотеза:     релиз checkout v2.14.1 в 03:40
Действие:     откат, ожидаемый эффект — 3 минуты
Следующий апдейт: 04:15

Восемь строк, тридцать секунд на заполнение: каждый подключившийся получает состояние без единого вопроса.

Наружу. Три правила, каждое оплачено чужими ошибками:

  1. Статусная страница живёт вне вашей инфраструктуры. В отказе AWS Kinesis 25 ноября 2020 года инструменты обновления собственной статусной страницы зависели от пострадавших сервисов — сообщать об аварии пришлось окольными путями. Хостинг статуса у стороннего провайдера стоит десятки USD в месяц и покупает единственную вещь, которая нужна в такой момент: способность говорить.
  2. Не называйте срок восстановления, пока не знаете причину. «Починим за полчаса» без понимания причины — это обещание, которое вы нарушите публично. Честная формулировка: «работаем, следующее обновление в 04:30».
  3. Не врите про масштаб. «Небольшая часть пользователей» при 48 % отказов — это ложь, которую клиенты проверят по своим графикам. Репутационная стоимость пойманного преуменьшения выше стоимости самой аварии.

Журнал: механизм, а не бюрократия

Журнал ведут не ради отчётности. Ведут потому, что память об инциденте деградирует за часы. Через сутки участники искренне помнят упорядоченную, логичную историю, которой не было: мозг задним числом достраивает причинность и убирает тупики. Восстановить по логам можно действия, но не гипотезы и не решения — а именно они интересны в постмортеме. Что фиксировать: метка времени, факт (наблюдение), решение, действие, результат. Что не фиксировать: оценки людей, «Петя опять», формулировки, которые вы не хотели бы увидеть в публичном документе. Минимальная автоматизация — скрипт, который создаёт скелет за пару секунд:

#!/usr/bin/env bash
# incident-open.sh — каталог, журнал и снимок контекста за пару секунд.
set -euo pipefail
SEV="${1:?уровень: SEV1|SEV2|SEV3}"; SUMMARY="${2:?симптом одной строкой}"
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"; DIR="incidents/INC-$(date -u +%Y%m%d-%H%M)"
mkdir -p "$DIR"
printf '# %s · %s\n\n| Время (UTC) | Кто | Что |\n|---|---|---|\n| %s | инициатор | открыт: %s |\n' \
  "${DIR##*/}" "$SEV" "$TS" "$SUMMARY" > "${DIR}/timeline.md"

# Снимок того, что через час будет недоступно: история деплоев прокрутится,
# флаги переключат, состояние внешней пробы забудут.
{
  kubectl rollout history deployment --all-namespaces 2>/dev/null | tail -20 || echo "деплои: нет данных"
  curl -fsS --max-time 5 "${FLAGS_URL:-http://flags/api/v1/enabled}"       || echo "флаги: нет данных"
  curl -fsS --max-time 5 -o /dev/null -w 'проба http=%{http_code} t=%{time_total}s\n' \
       "${PROBE_URL:-https://example.com/healthz}"                         || echo "проба не отвечает"
} >> "${DIR}/snapshot.md" 2>&1
echo "Создан ${DIR}. Дальше — объявить себя командиром и заполнить шаблон."

Ключевая часть здесь — не создание каталога, а снимок контекста: то, что не сняли в первые минуты, восстановлению не подлежит. Для команд, которым мало текстового файла, есть боты и платформы — Slack-воркфлоу на 30 строк, PagerDuty, incident.io, FireHydrant, Rootly; но разница между ними меньше, чем разница между «есть шаблон» и «нет шаблона».

Эскалация: таймбоксы и честная арифметика

Эскалация — это не «сдался», а операция с известной стоимостью и известной пользой; считать надо и то и другое. Правила-таймбоксы, не требующие обсуждения в 04:00:

  • Нет правдоподобной гипотезы через 15 минут после подтверждения → зовём владельца сервиса.
  • Нет митигации через 30 минут → зовём вторую линию или руководителя дежурства.
  • Инцидент длится больше 2 часов → меняем командира, даже если «уже почти».
  • Затронуты данные или безопасность → зовём сразу, без таймбокса.

Формулировка важна: «через 15 минут без гипотезы обязан позвать» снимает с дежурного решение и вместе с ним — стыд. Дежурный, который не позвал, потому что не хотел выглядеть слабым, — это дефект процесса, а не характера.

Сколько это стоит. Посчитаем на конкретных числах, чтобы не спорить лозунгами. Сервис с оборотом 2 000 000 USD в месяц; не весь оборот теряется — часть покупателей вернётся позже; маржа 20 %, не возвращается 40 % несостоявшихся покупок. Ночной звонок второму инженеру стоит час ночью плюс примерно половину следующего рабочего дня, при полной стоимости часа 40 USD:

оборот в минуту   = 2 000 000 / 43 200 = 46,3 USD/мин
потеря маржи      = 46,3 × 0,20 × 0,40 = 3,7 USD/мин
цена звонка       = (1 + 4) × 40       = 200 USD
окупаемость       = 200 / 3,7          ≈ 54 минуты сокращения инцидента

И вот здесь надо быть честным: для небольшого сервиса прямая денежная арифметика эскалацию часто не оправдывает. Пятьдесят четыре минуты — много. Означает ли это «не звонить»? Нет, означает, что решение принимается по другим критериям, и надо называть их прямо. Риск ошибки уставшего человека: инженер, который час бьётся в одиночку ночью, принимает решения заметно хуже дневного — депривация сна даёт эффект, сопоставимый с алкогольным опьянением (Dawson и Reid, Nature, 1997; см. главу про дежурство), а ручная правка данных в 05:00 в одиночку превращает сорокаминутную аварию в трёхдневное восстановление. Отток и репутация не входят в формулу: клиент, у которого второй раз за месяц не прошла оплата, уходит, и его уход в стоимости минуты не отражается. Эффект масштаба: тот же расчёт при обороте 200 000 000 USD в месяц даёт 370 USD/мин, и звонок окупается, если экономит 33 секунды, — поэтому у крупных «звони немедленно» не культура, а арифметика.

Вторую половину арифметики — сколько бюджета сожрал конкретный инцидент — удобно считать скриптом, а не в уме на телефоне:

"""Арифметика инцидента. Сложность — O(1) по времени и памяти:
это счёт над несколькими числами, структуры данных здесь не нужны."""


def budget_minutes(target: float, window_days: int = 30) -> float:
    """Бюджет ошибок в минутах полного отказа за окно SLO."""
    return window_days * 24 * 60 * (1 - target)


def burned(target: float, duration_min: float, bad_fraction: float = 1.0) -> dict:
    """bad_fraction — доля затронутых запросов (1.0 = полный отказ)."""
    budget = budget_minutes(target)
    equivalent = duration_min * bad_fraction   # «эквивалент полного отказа»
    return {
        "эквивалент_минут": round(equivalent, 1),
        "доля_бюджета": round(equivalent / budget, 3),
        "остаток_минут": round(budget - equivalent, 1),
        "таких_инцидентов_в_месяц": int(budget // equivalent) if equivalent else None,
    }


print(f"бюджет: {budget_minutes(0.999):.1f} мин/мес")
print("A:", burned(0.999, 38))                # «сначала понять»: откат на 38-й минуте
print("B:", burned(0.999, 12))                # «сначала вернуть»: откат на 12-й
print("частичный:", burned(0.999, 40, 0.25))  # 25 % запросов в течение 40 минут
бюджет: 43.2 мин/мес
A: {'эквивалент_минут': 38.0, 'доля_бюджета': 0.88, 'остаток_минут': 5.2, 'таких_инцидентов_в_месяц': 1}
B: {'эквивалент_минут': 12.0, 'доля_бюджета': 0.278, 'остаток_минут': 31.2, 'таких_инцидентов_в_месяц': 3}
частичный: {'эквивалент_минут': 10.0, 'доля_бюджета': 0.231, 'остаток_минут': 33.2, 'таких_инцидентов_в_месяц': 4}

Строчка 'таких_инцидентов_в_месяц': 1 — самая полезная в выводе: она переводит абстрактное «мы держим три девятки» в понятное — при таком качестве реакции вы можете позволить себе одну аварию в месяц. Если аварий три, обсуждать надо не героизм дежурных, а либо SLO, либо ёмкость, либо безопасность релизов.

Длинные инциденты: смены, передача, усталость

Инцидент длиннее двух-трёх часов — отдельный жанр. Здесь ломается не техника, а люди: внимание командира падает, состояние в его голове перестаёт соответствовать реальности, и появляются решения, которые утром выглядят необъяснимыми. Жёсткое правило: командир меняется не позже чем через 2–4 часа, даже если «сейчас дочиню»: это не признак провала, а плановая процедура, такая же, как смена пилота в длинном перелёте. Формат передачи занимает три минуты и произносится вслух или письменно целиком, даже если новый командир всё читал:

ПЕРЕДАЧА КОМАНДОВАНИЯ · 06:40 · INC-2026-0731-01
Что происходит:   лаг репликации 40 минут, чтения отдают старые данные
Что подтверждено: не сеть (проверено), не диск (проверено), не релиз (откат не помог)
Что исключено:    гипотеза «долгая транзакция» — не подтвердилась в 05:20
Что сейчас делаем: снимаем pg_stat_activity каждые 30 сек, ищем блокировки
Кто в деле:       @anna (оператор), @dmitry (связь), @sergey (DBA, подключён 06:10)
Что нельзя:       фейловер вручную без решения нового командира
Следующий шаг:    в 07:00 решение — фейловер или ждём
Принял командование: @olga, 06:42

Пункт «что исключено» ценнее всех остальных: без него новый командир потратит час на проверку уже проверенного. Это тот же принцип, что в разборе распределённых отказов — сужение пространства гипотез стоит дорого, терять его нельзя.

После инцидента. Ночной инцидент длиннее часа означает, что участники следующий день не работают — не «могут не работать», а не работают. Это правило принимается один раз и потом не обсуждается в каждом отдельном случае, потому что человек, только что вытащивший компанию из аварии, психологически не в состоянии сказать «я сегодня не приду». Отсюда простая проверка зрелости процесса: если после ночного инцидента люди приходят к 10:00 и делают вид, что всё нормально, ваш процесс реакции работает за счёт запаса здоровья сотрудников, и этот запас конечен. Подробнее — глава про дежурство, и это ровно та точка, где инженерное решение упирается в организационное: техническими средствами усталость не лечится.

Особые случаи, где обычный порядок не работает

Потеря или порча данных. Правило «сначала митигируй» отменяется. Первое действие — остановиться и зафиксировать состояние: снапшот, стоп записи, отключение фоновых джобов. Каждая минута работающей системы с испорченными данными увеличивает объём того, что придётся распутывать. Второе — оценить, что именно потеряно, и только потом чинить. История GitLab — про это: попытка ускорить восстановление привела к необратимому удалению.

Инцидент безопасности. Другой процесс: приоритет не восстановление, а сохранение улик и прекращение доступа. Перезапуск скомпрометированного контейнера уничтожает следы, откат может вернуть уязвимую версию, а «починим и разберёмся» законодательно недопустимо, если затронуты персональные данные. Такие инциденты объявляются отдельным типом со своим списком участников — см. трек по безопасности, главу про моделирование угроз и главу про приватность и соответствие требованиям.

Отказ у провайдера. Ваши возможности ограничены, но обязанности — нет. Что делать: подтвердить внешними источниками, включить деградацию (кэш, очередь на потом, ограниченный режим), сообщить клиентам честно — «проблема на стороне облачного провайдера, следим». Чего не делать: обещать сроки со ссылкой на чужую статусную страницу и повторять её формулировки как свои. Ответственность перед вашим клиентом — ваша, даже когда причина чужая.

Каскадный отказ. Отдельная механика: перегрузка одного узла перекладывает нагрузку на соседей, они падают тоже, и восстановление не наступает даже после устранения исходной причины, потому что накопившиеся ретраи добивают систему при каждой попытке подняться. В инциденте это опознаётся по симптому «починили, но не поднимается». Стандартное действие — сбросить нагрузку: отключить трафик, дать системе подняться пустой, впускать пользователей порциями. Механику разбирает глава про режимы отказа; с точки зрения системного мышления это та же усиливающая петля, что и в разделе про координацию, только из запросов вместо людей — и лечится она одинаково: размыканием контура.

Метрики процесса и как их испортить

Честный набор — с указанием, где именно теряется время:

Метрика Что меряет Типичный рычаг
TTD, time to detect отказ начался → мониторинг заметил пороги и окна алертов
TTA, time to acknowledge алерт → человек принял расписание, эскалация, шум
TTE, time to engage принял → собраны нужные люди роли, шаблон, автоматика создания канала
TTM, time to mitigate собрались → пользователю снова хорошо флаги, откат, деградация
TTR, time to resolve до устранения причины относится к постмортему, не к дежурству

Разложим сорок одну минуту из первого абзаца:

TTD  03:47 → 03:52   5 мин   алерт с окном 5 минут
TTA  03:52 → 03:54   2 мин   дежурный проснулся
TTE  03:54 → 04:19  25 мин   ролей нет, все делают всё, двое затёрли друг друга
TTM  04:19 → 04:33  14 мин   вопрос «а релиз был?» + откат
------------------------------------------------
                    41 мин   из них 25 — чистая координация

Шестьдесят процентов инцидента — TTE. Это хорошая новость: самая большая часть чинится не архитектурой, а шаблоном сообщения и договорённостью о ролях.

Как эти метрики портятся. Закон Гудхарта работает и здесь: как только MTTR становится целевым показателем команды, у людей появляется дешёвый способ его улучшить — не объявлять инциденты. Мелкие аварии перестают попадать в статистику, средняя длительность падает, отчёт зеленеет, а надёжность не меняется вовсе. Симметричный эффект — понижение SEV задним числом. Защита: считайте не только MTTR, но и количество объявленных инцидентов и долю выгоревшего бюджета, и смотрите на них вместе. Резкое падение числа инцидентов при неизменной доле бюджета — не успех, а сигнал, что процесс перестал срабатывать. Про то, почему любая метрика, ставшая целью, начинает искажаться, — глава про локальную оптимизацию. И ещё: сравнивать MTTR между командами бессмысленно. У одних «инцидент» — это SEV1 раз в квартал, у других — любое срабатывание алерта. Метрика имеет смысл только как ряд внутри одной команды с неизменным определением.

Цена процесса

Раздел, который в методичках обычно отсутствует. Процесс стоит внимания. Роли, шаблоны, каденция обновлений — это работа, которую делают вместо починки. При инциденте с одним участником и понятной причиной весь ритуал — чистые накладные расходы. Поэтому SEV3 в конфиге выше почти ничего не требует: процесс должен масштабироваться вниз, иначе люди начнут его обходить.

Инцидент-театр. Симптомы: голосовой мост на двенадцать человек, из которых работают двое; обязательная презентация для руководства к утру; поле «бизнес-влияние в рублях» в шаблоне, которое никто не может заполнить; SEV-уровень, назначаемый по политическим соображениям. Театр опознаётся по признаку: действия, не сокращающие ни одну из метрик выше. Каждое такое действие оплачивается временем людей, которые в этот момент могли чинить.

Ложные инциденты тоже стоят. «Объявлять дёшево» — верно, но не бесплатно. Если из двадцати объявлений восемнадцать оказались ложными, вы получите ту же историю, что с шумными алертами: люди перестанут реагировать. Разница между «шумный алерт» и «шумный инцидент» только в масштабе разбуженных.

Люди — самый дорогой ресурс процесса. Три ночных инцидента подряд означают, что вся команда работает вполсилы неделю. Это не «мягкость», это расчёт: неделя работы вполсилы для команды из пяти человек — это примерно 100 человекочасов, дороже почти любой из аварий, которые их вызвали.

Где это упирается в организацию, а не в инженерию. Роль связи требует человека, которого не будут дёргать в консоль, — штатной единицы или явной договорённости с руководством. Выходной после ночного инцидента требует, чтобы кто-то согласился на сдвиг сроков. Правило «повысить SEV может каждый» работает, только если за это ни разу никого не наказали. Запрет на диагностику до митигации требует, чтобы никто не спрашивал «а вы уверены, что откат был нужен». Смена командира через два часа требует второго обученного командира — то есть инвестиции в обучение до аварии, а не во время. Каждый из этих пунктов — организационное решение с ценником. Инженер может их предложить и обосновать арифметикой из этой главы, но принять — нет. Честная позиция: если организация не готова, работайте с тем, что есть, и фиксируйте отсутствующее в постмортемах как системный фактор — это единственный законный способ сделать проблему видимой.

Что переносится из Google SRE, а что нет

Глава 14 книги SRE и глава 9 SRE Workbook — лучший бесплатный материал по теме. Но они описывают организацию, где в любой момент суток есть дежурный командир инцидента, не занятый ничем другим. У большинства читателей такой роскоши нет. Переносится без изменений и стоит ноль: разделение «командует» и «чинит» — даже между двумя людьми; захват роли вслух с меткой времени; один канал как единственный источник истины и запрет на личку; митигация раньше диагностики с критерием закрытия по восстановлению функции; шаблон объявления и журнал с метками времени; таймбокс на гипотезу; право любого повысить уровень серьёзности.

Переносится с оговорками: отдельные роли связи и журналиста оправданы при пяти и более участниках либо при инциденте длиннее часа, при двух это лишний оверхед; голосовой мост полезен от пяти участников, при двух он медленнее текста и не оставляет журнала; смена командира каждые 2–4 часа требует второго обученного командира — если его нет, это и есть ваша задача на ближайший квартал; тренировки IMAG заменяются получасовым разбором сценария раз в квартал — см. учения и chaos-эксперименты.

Не переносится: круглосуточный пул дежурных командиров; отдельная команда, принимающая и сортирующая входящие инциденты; допущение, что есть кому передать роль в любой момент; допущение, что участники инцидента не являются одновременно единственными авторами затронутого кода; масштаб, при котором основная задача командира — координация между десятками сервисных команд. У вас основная задача — не дать трём людям мешать друг другу.

Минимальная работающая конфигурация для команды из трёх–пяти человек:

  1. Определение инцидента через долю бюджета ошибок — одна таблица.
  2. Один канал, куда пишут всё, и закреплённый в нём шаблон объявления.
  3. Роль командира — по умолчанию дежурный; «я командир» пишется вслух.
  4. Руки в проде у одного человека; два таймбокса — 15 минут на гипотезу, 30 на эскалацию.
  5. Статусная страница вне вашей инфраструктуры.

Пять пунктов, помещаются на одну страницу, внедряются за день. Развёрнуто про «SRE в маленькой команде» — в финальной главе трека.

Типичные ошибки

  • Командир чинит. Через десять минут состояние никто не держит, а гипотезы перестают проверяться по списку.
  • Роли не названы поимённо. «Кто-нибудь посмотрит базу?» — не назначение, никто не посмотрит. Следом приходит вторая беда: руки в проде у нескольких человек, они затирают изменения друг друга, и система становится ненаблюдаемой.
  • Диагностика вместо митигации. «Сейчас пойму и точечно починю» — самый дорогой инстинкт в инциденте.
  • Решения в личке. Подключившийся через двадцать минут начинает с нуля и задаёт уже отвеченные вопросы.
  • Нет журнала. Постмортем через два дня становится художественным пересказом, а таймлайн — археологией.
  • Не объявили, чтобы «не поднимать шум». Самая дорогая ошибка: люди подключаются по одному, каждый со своей картиной. Родственная — понижение SEV задним числом ради отчётности.
  • Обещание срока восстановления до понимания причины. Публично нарушенное обещание дороже самой аварии.
  • Закрыт по факту найденной причины, а не по восстановлению — люди сидят в аварийном режиме лишние часы. Или наоборот, закрыт слишком рано: без окна наблюдения 15–30 минут инцидент открывается заново, и вторая побудка бьёт по доверию сильнее первой.
  • Начальник в координационном канале. Даже молча присутствующий руководитель меняет поведение участников; его место — в статусном канале.
  • Единственное действие по итогам — новый алерт. Почти всегда означает, что причину не нашли (про постмортемы).

Мини-итог

  • Инцидент определяется порогом, а не ощущением: доля сожжённого бюджета плюс необходимость координации. При SLO 99,9 % бюджет — 43,2 минуты в месяц, поэтому 5 % бюджета — это 2,2 минуты полного отказа, и почти любая заметная авария объявляется.
  • Объявлять должно быть дёшево, а закрытие с пометкой «не подтвердилось» — нормальный исход: ложное объявление стоит пять минут, неназванный инцидент — десятки.
  • Роли существуют ради арифметики связей: без ролей каналов n(n−1)/2 — O(n²), со звездой n−1 — O(n). Шесть человек без ролей — 15 каналов, с командиром — 5.
  • Командир не чинит. Оператор — единственные руки в проде. Связь буферизует внешние вопросы. Журналист пишет метки времени. В маленькой команде роли совмещаются, но разделение «голова/руки» сохраняется даже вдвоём.
  • Первые минуты: подтвердить с независимой точки → объявить и назвать себя командиром → спросить «что изменилось, кто страдает, что уже пробовали» → митигировать. Разница между «сначала понять» и «сначала вернуть» на нашем примере — 38 минут против 12, то есть 60 % месячного бюджета.
  • Митигация раньше диагностики: флаг, откат, деградация применимы без понимания причины и обратимы. Ручная правка данных быстра и необратима — только по решению командира и вдвоём. Cloudflare в 2019-м выключил WAF целиком за 27 минут вместо часов поиска виноватого правила.
  • Канал — это запись; чего нет в канале, не произошло. Закольцованная связь («принято: откатываю checkout с v2.14.1») снимает целый класс ошибок за десять секунд, а статусная страница обязана жить вне вашей инфраструктуры.
  • Эскалация по таймбоксу, а не по самооценке: 15 минут без гипотезы, 30 без митигации, 2 часа — смена командира. Денежная арифметика оправдывает звонок только на больших оборотах (54 минуты окупаемости при 2 млн USD/мес против 33 секунд при 200 млн); на малых решение обосновывается риском ошибки уставшего человека.
  • 60 % длительности плохо организованного инцидента — TTE, время на сбор людей: чинится шаблоном и договорённостью, а не архитектурой. MTTR как цель ломает сам себя (дешевле всего улучшить его, перестав объявлять инциденты), поэтому смотрят его вместе с числом инцидентов и долей сожжённого бюджета.
  • Процесс стоит внимания, ложные объявления обесценивают канал, ночные инциденты выжигают людей. Выходной после ночной аварии, штатная роль связи и второй обученный командир — организационные решения с ценником: инженер может их обосновать арифметикой, но не принять.

Источники

Что дальше

Инцидент закрыт: пользователям снова хорошо, журнал написан, люди спят. Причина при этом может быть до сих пор неизвестна — и это нормально, у неё другой дедлайн. Дальше начинается работа, которая определяет, случится ли то же самое ещё раз: разбор без поиска виноватых (не из доброты, а потому что при поиске виноватых перестают поступать данные) и, что сложнее, доведение выводов до реальных правок в коде и процессах.

Постмортемы: почему без обвинения и как довести до правок

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов