SRE и надёжность Дежурство: расписание, эскалация и цена для людей
0%

Дежурство: расписание, эскалация и цена для людей

Дежурство: расписание, эскалация и цена для людей

03:41, среда. Телефон вибрирует на тумбочке. CheckoutErrorRateHigh. Инженер садится на кровати, минуту ищет очки, ещё две — ноутбук, ещё три уходит на VPN, потому что токен протух за неделю. В 03:52 он видит дашборд: доля 5xx на оформлении заказа — 34 %. В 03:58 находит в истории деплоев релиз, выкатившийся в 22:10. В 04:03 нажимает откат. В 04:07 графики зелёные. В 04:40 он всё ещё лежит с открытыми глазами.

В 10:00 у него стендап, в 11:30 — код-ревью чужого PR, в 14:00 — проектирование новой фичи. Он проведёт этот день в состоянии, при котором в большинстве стран ему нельзя было бы сесть за руль. Никто не сочтёт это происшествием: релиз откатили за 26 минут, инцидент закрыт, дежурство сработало.

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

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

Предполагается, что вы уже прочли главы про SLI и SLO, бюджет ошибок и алерты: дежурство — это то, что происходит после того, как алерт всё-таки сработал.

Дежурство — это контракт из трёх пунктов, а не «быть на связи»

Формулировка «Петя на этой неделе на связи» не является расписанием дежурства. Она не отвечает ни на один из вопросов, которые возникнут в 03:41. Работающее определение:

Дежурство — это оплаченное обязательство отреагировать на сигнал за фиксированное время, обладая заранее выданными полномочиями что-то сделать.

Три части, и все три обязательны:

  1. Покрытие. Какие часы, какие сервисы, какие классы сигналов. «Круглосуточно» — не покрытие, а лозунг: если в команде четыре человека, круглосуточно означает конкретное расписание с конкретной ценой, и её нужно назвать.
  2. Время отклика. Сколько минут от доставки уведомления до подтверждения (ack) и сколько — до первого содержательного действия. Числа не берутся из вежливости, они выводятся из бюджета ошибок; ниже посчитаем.
  3. Полномочия. Что дежурный имеет право сделать сам, без чьего-либо разрешения. Это самый часто пропускаемый пункт и самый дорогой: без него любая эскалация превращается в поиск того, кто разрешит.

Уберите третий пункт — и первые два бессмысленны. Дежурный с временем отклика в пять минут и без права откатить релиз просто быстрее начнёт кому-то звонить.

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

Арифметика покрытия: сколько людей нужно на 168 часов

В неделе 7 × 24 = 168 часов. Разложим их с точки зрения дежурного, у которого рабочий день с 10:00 до 19:00 в будни:

Зона Как считается Часов в неделю
Рабочие часы 5 дней × 9 часов 45
Вне работы, но бодрствую 168 − 45 − 49 74
Ночь, 00:00–07:00 7 дней × 7 часов 49
Всего 168

Неделя дежурства: 168 часов, разложенные на рабочие, нерабочие и ночные, с отметками страниц

Ключевое наблюдение из этой картинки: оплачивается обычно только синяя зона, а занята вся сетка. 123 часа вне рабочего времени — это не «свободное время, в которое иногда звонят». Это время, в которое нельзя уехать за город, выпить бокал вина, уйти в бассейн, сесть в самолёт, уложить ребёнка, оставив телефон в другой комнате. Экономисты называют такое ограничение on-call constraint, и его стоимость не равна нулю даже при нуле срабатываний.

Теперь расписание. При недельной ротации primary в команде из N человек каждый дежурит 52 / N недель в год:

Размер ротации Недель в год Часов под пейджером Из них ночных Страниц в год при 10 в неделю Ночных пробуждений в год
3 17,3 2 912 849 173 51
4 13,0 2 184 637 130 38
5 10,4 1 747 510 104 30
6 8,7 1 456 425 87 25
8 6,5 1 092 318 65 19
10 5,2 874 255 52 15

Доля ночных страниц взята как 49 / 168 = 29,2 % — то есть в предположении, что поломки не выбирают время суток. На практике ночью меньше трафика, но и меньше людей, которые заметят проблему раньше алерта, так что оценка не оптимистичная.

Прочитайте нижнюю строчку и верхнюю рядом. Команда из десяти при том же качестве системы даёт 15 ночных пробуждений на человека в год — примерно одно в три недели, это переживаемо. Команда из трёх даёт 51 — то есть каждую неделю кого-то будят, а конкретного инженера будят каждую вторую его ночь на дежурстве. Разница не в дисциплине и не в стойкости людей, а в делителе.

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

Ловушка secondary

Схема «primary + secondary» кажется бесплатной: второй эшелон почти никогда не будят. Но часы под пейджером она удваивает. В команде из шести человек с двумя ролями каждый оказывается на дежурстве 52 × 2 / 6 = 17,3 недели в год — то есть треть года кто-то из ваших шести живёт с телефоном под рукой, хотя ночных пробуждений у него по-прежнему 25, а не 50.

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

Правило смежности

Один приём стоит ноль и работает всегда: secondary текущей недели становится primary следующей. Человек входит в смену, уже зная, что горело последние семь дней, какие правки не доехали и какой релиз выкатывается в среду. Передача контекста происходит сама, без ритуала.

Обратите внимание на третью неделю: Вера в отпуске, её подменяет Глеб, который на предыдущей неделе был secondary. Замены — не исключение, а норма: отпуска, болезни, командировки, конференции. Расписание, которое не переживает отпуск одного человека, не является расписанием.

Форматы расписания и чего они стоят

Схема Что даёт Чем платите Когда разумно
Недельная ротация primary простота, контекст держится всю неделю одна тяжёлая неделя целиком ротация от 5–6 человек
Primary + secondary страховка на непринятый звонок удвоение часов ограничения критичный сервис, ротация от 8
Разрез недели: будни / выходные выходные делятся честно, короче отрезки больше передач смены команды, где выходные особенно ценят
Смены по 12 часов нормируемая нагрузка, никто не спит с пейджером нужно вдвое больше людей одновременно своя площадка поддержки, крупный масштаб
Follow-the-sun ночных дежурств нет вообще ни у кого нужны 2–3 команды в разных поясах компания с офисами в разных регионах
Только рабочие часы ноль ночного износа ночью инциденты длятся до утра сервисы, где это согласовано с бизнесом

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

Отдельно про follow-the-sun. Схема выглядит идеально: ночных дежурств нет ни у кого, потому что ночь одной площадки — рабочий день другой. Цена, которую редко называют: контекст рвётся на границах смен, ранбуки обязаны быть исчерпывающими и на общем языке, инцидент часто передают в разгаре, и появляется класс проблем «передали не то и не тому». Схема требует не столько трёх часовых поясов, сколько трёх команд, которые действительно умеют работать с одной кодовой базой. Ниже примерно двухсот инженеров это почти никогда не окупается.

Эскалация: не вежливость, а статья расхода бюджета

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

Напомним курс. Окно 30 дней — это 30 × 24 × 60 = 43 200 минут. При SLO 99,9 % бюджет равен 43 200 × 0,001 = 43,2 минуты в месяц. Это весь допустимый простой за месяц: меньше сорока пяти минут.

Теперь разберём один ночной инцидент по минутам.

Разбор минут ночного инцидента на фоне месячного бюджета ошибок

Разложение по источникам задержки:

Отрезок Минут Кто «тратит» Чем сокращается
Окно правила до срабатывания 3 машина короче окно — больше ложных срабатываний
Доставка уведомления 1 машина несколько каналов, но без дублирования
Ожидание ack от primary 5 таймаут политики короче таймаут — чаще будят двоих
Ack от secondary 2 человек привычка держать телефон у кровати
Подъём, ноутбук, VPN, дашборд 6 человек долгоживущий токен, закладки, готовый дашборд
Гипотеза и её проверка 6 человек ранбук, свежие дашборды, тренировки
Митигация (откат) 4 машина автооткат, флаги, размыкатели
Итого 27

Из 27 минут 19 — это разбуженный человек, то есть 70 %. И вот здесь начинается собственно инженерия, а не увещевания.

Первое. Таймаут эскалации — это параметр с ценником. Пять минут ожидания ack = 5 / 43,2 = 11,6 % месячного бюджета, потраченные на тишину. Если primary пропускает каждый пятый звонок, а страниц в месяц десять, то две эскалации по таймауту съедают 10 / 43,2 = 23 % бюджета за месяц — просто на ожидание. Отсюда практика: таймаут 3–5 минут ночью, 10–15 минут днём (днём человек за компьютером, ему не нужно просыпаться, но он может быть на встрече).

Второе. Если primary отвечает за две минуты и эскалации нет, цепочка сокращается до 3 + 1 + 2 + 6 + 6 + 4 = 22 минут, это 51 % бюджета. То есть два таких инцидента за месяц исчерпывают бюджет 99,9 % полностью (22 + 27 = 49 > 43,2), и дальше начинается разговор про заморозку релизов из главы про бюджет ошибок.

Третье, самое важное. При SLO 99,95 % бюджет равен 21,6 минуты в месяц — меньше, чем длится один разобранный выше инцидент. При 99,99 % бюджет 4,32 минуты, и одно только окно правила съедает 70 % от него. Вывод не в том, что дежурный медленный: начиная примерно с 99,95 % человек в контуре арифметически не успевает, и SLO должна защищать автоматика — автооткат, размыкатели, деградация (глава 10), безопасные релизы (глава 13). Человек в такой схеме приходит не чинить, а разбираться, почему автоматика сработала.

Это тот же аргумент, что и в главе про алерты, только теперь он проведён по всей цепочке, а не по её началу.

Жизненный цикл страницы

Две ветки на этой схеме заслуживают отдельного внимания.

FIRE --> FLAP — страница, погасшая до того, как её кто-то увидел. Такие обязательно нужно считать отдельной метрикой: это чистый шум, который ещё не начал будить людей, но уже показывает, что порог выбран неправильно.

ACK --> ESC3 — эскалация по запросу, а не по таймауту. Это принципиально другое событие, и в статистике их нельзя смешивать. Эскалация по таймауту — сбой процесса. Эскалация по запросу — корректная работа процесса: дежурный понял, что не справляется, и позвал помощь. Если в вашей команде эскалация по запросу читается как «не справился», её перестанут использовать, и вы будете получать сорокаминутные инциденты, которые решаются за три минуты человеком, знающим систему. Это ровно тот же механизм, что и с постмортемами без обвинения (глава 8): как только за сигнал начинают наказывать, сигнал исчезает, а явление остаётся.

Политика эскалации как конфигурация

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

# Политика эскалации для сервиса checkout.
# Правило: каждая ступень отвечает на вопрос «а если предыдущая молчит».
escalation_policy:
  name: checkout-critical
  # Что делать с повторными срабатываниями того же алерта,
  # пока инцидент открыт: не будить второй раз.
  repeat_while_open: false

  steps:
    - level: 1
      targets: [schedule://checkout-primary]
      channels: [push, call]        # ночью — обязательно звонок, push пропускают
      timeout_minutes: 5

    - level: 2
      targets: [schedule://checkout-secondary]
      channels: [push, call]
      timeout_minutes: 5

    - level: 3
      # Последняя ступень адресуется РОЛИ, а не человеку:
      # люди меняются, роль остаётся.
      targets: [role://engineering-lead, channel://incidents]
      channels: [push, call, chat]
      timeout_minutes: 10

    - level: 4
      # Тупик обязателен: политика без последней ступени
      # молча теряет инциденты в 4 утра.
      targets: [role://head-of-engineering]
      channels: [call]

  # Дневные и ночные таймауты различаются: днём человек за компьютером.
  overrides:
    - when: "Mon-Fri 10:00-19:00 Europe/Moscow"
      steps_timeout_minutes: 12

Три вещи, которые ломаются чаще всего:

  • Нет последней ступени. Политика заканчивается на secondary, и если оба спят, инцидент висит до утра. Последней ступенью всегда должен быть кто-то, кого точно разбудят, — обычно роль, а не имя.
  • Адресация людям, а не ролям и расписаниям. Человек уходит в отпуск или из компании, а его имя остаётся в конфиге. Ссылайтесь на schedule:// и role://.
  • Повторное оповещение при открытом инциденте. Дежурный уже работает, а пейджер продолжает звонить каждые пять минут — это активная помеха, которая удлиняет инцидент.

Полномочия: список, написанный до дежурства

Самая дорогая ночная минута — та, которую дежурный тратит на выяснение, можно ли ему что-то сделать. Полномочия фиксируются письменно, лежат рядом с расписанием и пересматриваются раз в квартал.

Действие Дежурный делает сам Комментарий
Откатить релиз да, без согласования самое частое и самое эффективное действие
Выключить фичу флагом да см. безопасные релизы
Включить деградацию: отдать кэш, отключить рекомендации да сценарии описаны заранее
Масштабировать до заранее оговорённого потолка да потолок в деньгах, например «до 3× от базы»
Разбудить любого инженера компании да без объяснений перед тем, как звонить
Объявить инцидент высокого уровня да лучше ложная тревога, чем поздняя
Опубликовать сообщение на статус-странице по шаблону шаблоны заготовлены, чтобы не сочинять в 4 утра
Изменить схему БД, удалить или восстановить данные нет только через эскалацию, вдвоём
Отключить конкретного клиента или заблокировать трафик по стране нет юридические и коммерческие последствия
Выкатить новый код с исправлением нет ночью ночью только откат и митигация — см. ниже про сон

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

Если какое-то из «да» у вас на практике «нет» — например, доступы на прод выдаются только через тикет с одобрением, — это конфликт политики доступа и времени реакции. Он решаемый (временные привилегии на смену, break-glass-доступ с логированием и обязательным разбором постфактум), но решается он не дежурным в 4 утра. Смежная тема — в главе про управление секретами.

До смены и после: подготовка и передача

Проверка перед началом смены занимает пятнадцать минут и экономит ту самую половину бюджета:

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

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

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

Передача смены — письменная, в общий канал, по шаблону:

## Передача смены: 15.06 → 22.06, сервис checkout

**Дежурил:** Глеб. **Принимает:** Дина.

### Что горело
- 16.06 03:41 `CheckoutErrorRateHigh` — релиз 4.19.2, откачено.
  Причина: таймаут к платёжному провайдеру поднят с 2 до 8 с. Тикет PAY-812.
- 18.06 14:20 `LatencyP99` — всплеск на 6 минут, само ушло.
  Гипотеза: перебалансировка партиций. Не подтверждено, тикет OBS-77.

### Что заглушено
- `KafkaISRShrink` — silence до 24.06, ждём обновления брокеров. Не забыть снять!

### Что ожидается на неделе
- 24.06 миграция таблицы orders, окно 02:00–04:00: дежурит команда БД, но алерты придут вам.
- Флаг `new_checkout_ui` раскатывается до 25 % в среду.

### Известные грабли
- VPN-токен живёт 7 суток, обновите до начала смены.
- Ранбук по `PaymentProviderDown` устарел, актуальная ссылка — в тикете PAY-799.

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

Цена для людей, посчитанная

Теперь центральная часть главы. Дежурство стоит дорого, и это можно измерить в трёх валютах: сон, свобода, деньги.

Сон

Одно ночное пробуждение — это не сорок минут инцидента. Это сорок минут инцидента плюс 30–60 минут повторного засыпания плюс фрагментация оставшегося сна. Реальная потеря — полтора-два часа, и качественно она хуже, чем просто «лёг на два часа позже».

Дальше — измеренные эффекты, а не общие слова:

  • Van Dongen и соавторы (2003) показали: 14 дней сна по 6 часов дают накопленный дефицит психомоторных функций, сопоставимый с двумя сутками полного лишения сна. Критично второе наблюдение той же работы: субъективная оценка сонливости при этом почти не растёт. Человек деградирует и не замечает этого — а значит, «я нормально себя чувствую» не является данными. DOI: 10.1093/sleep/26.2.117
  • Dawson и Reid (1997): 17 часов непрерывного бодрствования снижают психомоторные показатели примерно так же, как 0,05 % алкоголя в крови; 24 часа — как 0,10 %. DOI: 10.1038/40775
  • Landrigan и соавторы (2004): интерны в реанимации, работавшие по расписанию с длинными сменами, допускали на 36 % больше серьёзных врачебных ошибок, чем те же интерны на расписании с ограничением смен. Это прямой эксперимент, а не корреляция. DOI: 10.1056/NEJMoa041406

Сложите это с таблицей полномочий. Дежурный, разбуженный в 03:41 после полного рабочего дня, находится на восемнадцатом-двадцатом часу бодрствования. По данным Dawson и Reid, он в состоянии, при котором ему нельзя за руль. Именно поэтому строка «выкатить новый код с исправлением — нет ночью» является инженерным решением, а не проявлением недоверия: ночью разрешены только заранее описанные обратимые действия. Откат обратим. Флаг обратим. Написанный в 4 утра патч — нет, и второй инцидент, порождённый ночным исправлением первого, — классика жанра.

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

Свобода

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

Тут работает модель Карасека (1979): напряжение возникает не от высоких требований самих по себе, а от сочетания высоких требований с низким контролем. У дежурного контроль по определению минимален — время события выбирает не он. Значит, снизить износ можно не только снижением числа страниц, но и возвратом контроля:

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

Эти пункты стоят ноль рублей и дают заметный эффект именно потому, что бьют по второй переменной модели, а не по первой.

Деньги

Посчитаем стоимость круглосуточного покрытия одного сервиса. Пусть полная стоимость инженера для компании — 120 000 USD в год (зарплата, налоги, накладные), при 1 800 рабочих часах это 120000 / 1800 ≈ 67 USD в час.

Схема компенсации: 10 % ставки за каждый час «на связи» вне рабочего времени и 150 % за час активной работы ночью.

Primary, одна неделя:
  пассив:  123 ч × 67 USD × 0,10 = 824 USD
  актив:     3 ч × 67 USD × 1,50 = 302 USD
  итого                          = 1 126 USD за неделю
  за год (52 недели покрытия)    ≈ 58 500 USD

Secondary при половинной пассивной ставке (5 %):
  пассив:  123 ч × 67 USD × 0,05 = 412 USD
  актив:     1 ч × 67 USD × 1,50 = 101 USD
  итого                          ≈ 513 USD за неделю
  за год                         ≈ 26 700 USD

Круглосуточное двухэшелонное покрытие одного сервиса ≈ 85 000 USD в год.

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

Теперь вариант «мы не платим за дежурство, это входит в зарплату». Деньги никуда не делись — они конвертировались в текучесть. Оценки стоимости замены специалиста расходятся, но нижняя граница почти во всех исследованиях — 20–30 % годовой компенсации, а для дефицитных инженерных ролей она доходит до 100–200 % (Boushey, Glynn, Center for American Progress, 2012). При полной стоимости 120 000 USD даже консервативные 50 % дают 60 000 USD за один уход. Один дополнительный уход в год из-за дежурства съедает почти всю экономию на компенсации — и это до учёта потерянного знания системы, которое как раз и определяет скорость реакции в инциденте.

Тот же расчёт полезно проводить в обратную сторону, обосновывая инженерные работы. Если автооткат по метрике убирает 60 % ночных страниц, он экономит не только сон: при 25 ночных пробуждениях в год на человека и шести людях это 90 пробуждений команды, из которых 54 исчезают. Оцените их хотя бы по ставке активной работы — и получите число, которое можно положить в приоритизацию рядом с фичами. Смежная арифметика — в главе про юнит-экономику и в главе про рутину и автоматизацию.

Калькулятор, который стоит держать в репозитории

Вся модель умещается в две формулы: недель_под_пейджером = 52 · роли / N и ночных_пробуждений = (52 / N) · страниц_в_неделю · 49/168. Страницы получает только primary, часы ограничения — обе роли. Реализация:

"""Оценка годовой нагрузки на одного инженера в ротации дежурств."""

WEEK_HOURS = 168          # часов в неделе
WORK_HOURS = 45           # будни 10:00-19:00
NIGHT_HOURS = 49          # 00:00-07:00 каждый день
WEEKS_PER_YEAR = 52
NIGHT_SHARE = NIGHT_HOURS / WEEK_HOURS   # 0,292 — доля ночных часов


def oncall_load(team_size: int, pages_per_week: float, roles: int = 1) -> dict:
    """Нагрузка на одного человека за год.

    team_size     — сколько людей в ротации
    pages_per_week — сколько страниц генерирует сервис за неделю
    roles          — 1 (только primary) или 2 (primary + secondary)

    Сложность: O(1) по времени и O(1) по памяти.
    """
    if team_size < roles:
        raise ValueError("людей меньше, чем ролей в смене: расписание не существует")

    primary_weeks = WEEKS_PER_YEAR / team_size
    pager_weeks = WEEKS_PER_YEAR * roles / team_size
    pages = primary_weeks * pages_per_week

    return {
        "недель primary": round(primary_weeks, 1),
        "недель под пейджером": round(pager_weeks, 1),
        "часов под пейджером": round(pager_weeks * WEEK_HOURS),
        "из них ночных": round(pager_weeks * NIGHT_HOURS),
        "страниц в год": round(pages),
        "ночных пробуждений в год": round(pages * NIGHT_SHARE),
    }


def compensation_cost(hourly_rate: float,
                      passive_share: float = 0.10,
                      active_hours_per_week: float = 3.0,
                      active_multiplier: float = 1.5) -> float:
    """Годовая стоимость круглосуточного покрытия одной ролью. O(1)."""
    off_hours = WEEK_HOURS - WORK_HOURS            # 123 часа вне рабочего времени
    per_week = (off_hours * hourly_rate * passive_share
                + active_hours_per_week * hourly_rate * active_multiplier)
    return per_week * WEEKS_PER_YEAR


if __name__ == "__main__":
    for n in (3, 4, 6, 8, 10):
        print(n, oncall_load(n, pages_per_week=10))
    print(round(compensation_cost(67)))          # ≈ 58 500 USD в год

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

Петля, которая раскручивается сама

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

Здесь ровно три усиливающих контура, и каждый из них сам себя подпитывает:

  1. шум → усталость → медленнее реакция → длиннее инциденты → нет времени на правки → шум;
  2. усталость → уходы → меньше делитель → чаще дежурства → усталость;
  3. длиннее инциденты → сгорает бюджет → заморозка и аврал → усталость → длиннее инциденты.

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

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

Классическое проявление архетипа «латание вместо лечения» (разбор архетипов): дежурство — симптоматическое лечение, и чем лучше оно работает, тем меньше стимулов лечить причину. Хорошо отлаженная реакция на инциденты умеет прятать деградацию системы годами.

Метрики здоровья дежурства

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

Метрика Как считать Ориентир Что означает выход за границу
Страниц на смену всего страниц / число смен ≤ 2 на 12 часов система шумит или ломается
Ночных пробуждений на смену страницы 00:00–07:00 ≤ 1 на неделю пора платить или чинить
Доля actionable страницы, где дежурный что-то сделал ≥ 70 % правила пора чистить (глава 5)
Доля погасших самих FIRE → FLAP ≤ 5 % пороги и окна выбраны неверно
MTTA ночью медиана времени до ack ≤ 5 мин канал не будит либо человек выгорел
Эскалаций по таймауту доля от всех страниц ≤ 5 % сбой процесса, разбирать поимённо ротацию, не людей
Эскалаций по запросу доля от всех страниц 10–30 % — норма ноль означает, что боятся звать помощь
Смен без единой страницы доля смен ≥ 50 % здоровая система даёт тихие недели
Повторные страницы тот же алерт, та же причина тренд вниз первопричины не чинятся
Доля рутины в смене часов на toil / часов смены ≤ 25–30 % пора автоматизировать

Одну метрику стоит выделить особо, потому что она меняет разговор: число прерванных ночей команды за квартал. Не MTTR, не количество инцидентов, а именно ночи. Это число понятно всем — инженерам, руководителю, продакту, финансистам — и его нельзя переформулировать так, чтобы оно звучало нейтрально. «Мы сократили MTTR на 12 %» не производит никакого впечатления. «В прошлом квартале мы разбудили людей 47 раз, в этом — 12» производит.

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

Где инженерное решение упирается в организационное

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

Симптом Что чинится инженерно Где упирается
Много бесполезных страниц ревизия правил, алерты на скорость сжигания бюджета нужно право удалять алерты вопреки «а вдруг пригодится»
Одна и та же ручная операция каждую ночь скрипт, автооткат, автоскейл нужно время в спринте, а его выделяет не дежурный
Ночные релизы ломают прод запрет деплоя после 17:00, канареечные выкатки конфликт с «клиенту обещали сегодня»
Дежурный не может откатить выдать права, break-glass-доступ конфликт с политикой безопасности и аудитом
Ротация из трёх человек ничего нанять, объединить ротации или сузить покрытие — это деньги
Бюджет ошибок исчерпан, релизы всё равно катят ничего политика бюджета должна иметь силу, иначе она декоративна
Компенсации нет ничего решение уровня компании, не команды
После инцидента правки не делаются завести тикет с владельцем и сроком нужен приоритет выше нуля, а его даёт не инженер

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

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

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

Когда 24/7 невозможно: варианты для маленькой команды

Если вас трое, круглосуточное дежурство недостижимо в принципе — не потому, что вы недостаточно стараетесь, а потому что делитель равен трём. Честные варианты, по возрастанию цены:

1. Сузить покрытие и оформить это как договорённость. Ночью — best-effort, без обязательства реакции. Здесь нужно считать: при SLO 99,5 % бюджет равен 43 200 × 0,005 = 216 минут в месяц, то есть 3 часа 36 минут. Один ночной отказ, замеченный в 09:00 через шесть часов после начала, — это 360 минут, что превышает месячный бюджет в 1,7 раза. Значит, декларация «ночью best-effort» несовместима с 99,5 % на круглосуточном окне, и врать себе тут бесполезно. Работающие варианты:

  • SLO с окном на рабочие часы. Обязательство 99,9 % с 09:00 до 21:00 и отдельное, гораздо более скромное — на ночь. Так устроено большинство корпоративных SLA, и это нормально.
  • Ночью полный отказ невозможен по конструкции. Если ночью система деградирует, но не падает (кэш отдаёт устаревшие данные, очередь копит запросы, платежи ставятся в отложенную обработку), шестичасовое окно съедает не 360 минут бюджета, а сильно меньше — ровно поэтому деградация вместо отказа для маленькой команды важнее, чем для большой.

2. Заменить человека автоматикой там, где счёт идёт на минуты. Автооткат по метрике, размыкатели, автоскейл, health-check с выводом инстанса из балансировки. Для команды из трёх человек это не «продвинутая практика», а условие выживания: у вас физически нет второго эшелона.

3. Разделить страницы по критичности. Ночью будят только за «деньги не проходят» и «данные теряются». Всё остальное ждёт до утра в тикетах. Это требует честной классификации сервисов, зато сокращает ночные пробуждения кратно.

4. Объединить ротации соседних команд. Три команды по три человека дают ротацию из девяти — с 51 ночного пробуждения в год до 17. Цена: нужны ранбуки, понятные чужому человеку, и готовность будить владельца сервиса на второй ступени. Это самый недооценённый ход: он не требует денег, только работы над документацией.

5. Внешний первый уровень (NOC, дежурный провайдер). Работает только при отличных ранбуках: без них внешний дежурный добавляет 10 минут пересылки и ноль пользы. Хорошая проверка готовности — тот же критерий, что и для объединённой ротации.

6. Признать, что круглосуточная надёжность вам не нужна. Для B2B-сервиса с пользователями в одном часовом поясе, для внутренних систем, для инструментов разработки ночная недоступность может стоить существенно меньше, чем круглосуточное дежурство. Это продуктовое решение, и его нужно принять явно, а не по умолчанию.

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

Книга Site Reliability Engineering — лучший из существующих текстов про дежурство, и её одиннадцатая глава действительно стоит того, чтобы её прочли. Но её нормативы — это нормативы компании, где на один сервис приходится больше инженеров, чем у большинства читателей во всей компании. Разберём по пунктам.

Переносится почти без изменений, стоит ноль:

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

Переносится с оговорками:

  • «Не более двух инцидентов на смену 8–12 часов». Обоснование в книге разумное: качественная обработка инцидента вместе с постмортемом занимает около шести часов, значит в двенадцатичасовую смену помещается два. Но норматив предполагает, что дежурный не занят ничем другим. Если ваш дежурный параллельно тащит спринтовые задачи, реальный порог ниже — и начинать надо не с норматива, а с измерения: посчитайте, сколько у вас сейчас, а потом решайте, куда двигаться.
  • «Не более 50 % времени SRE на операционную работу». Правило требует существования второй половины и человека, который следит за пропорцией. В команде, где SRE и разработчик — один человек, соотношение измеряется, но не защищается. Измеряйте всё равно: видимая доля рутины — аргумент в разговоре о найме.
  • Пейджер как объект передачи. У Google SRE-команда может «вернуть пейджер» команде разработки, если сервис перестал соответствовать критериям. Это работающий механизм, но он держится на институциональной власти отдельной функции. Возвращать некому, если это одни и те же люди; аналог в маленькой команде — политика бюджета ошибок, у которой есть реальная сила.

Не переносится:

  • Ротации по 6–8 человек на каждой из двух площадок, то есть 12–16 инженеров на сервис.
  • Отдельная роль сортировщика инцидентов, отдельный коммуникатор, отдельный «писатель постмортемов».
  • Допущение, что вашу проектную работу на неделю дежурства подхватит кто-то другой.
  • Собственная платформа мониторинга, где стоимость лишней метрики близка к нулю.
  • Предположение, что дежурят по сервису, а не по всему, что есть в компании.

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

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

  • Расписание без замен. Первый же отпуск ломает ротацию, и дальше дежурят «кто согласился», то есть самые безотказные. Они же выгорают первыми.
  • Полномочия не выданы. Дежурный тратит первые пятнадцать минут на поиск того, кто разрешит откат. Это половина месячного бюджета при 99,9 %.
  • Эскалация читается как признание некомпетентности. Люди перестают звать помощь, инциденты удлиняются, а в отчётах это выглядит как «дежурный справился сам».
  • Адресация по именам, а не по ролям и расписаниям. Конфиг переживает уволившихся сотрудников на годы.
  • Нет последней ступени эскалации. Инцидент в 4 утра, оба дежурных спят, дальше в политике пусто.
  • Повторные оповещения при открытом инциденте. Пейджер мешает работать тому, кто уже работает.
  • Дежурному дают полноценные проектные задачи. Он либо не сделает их, либо не среагирует, либо сделает и то и другое плохо.
  • Ночной героизм поощряется публично. Похвала за подвиг превращает системную проблему в личную доблесть и снимает вопрос «почему вообще понадобился подвиг».
  • Ночные исправления кодом вместо отката. Второй инцидент, порождённый лечением первого, — самый частый сценарий двойной аварии.
  • Ротация «все дежурят одинаково» без учёта допуска. Человек на второй неделе в компании (про адаптацию новичков) в ротации primary приносит не помощь, а задержку: допуск к дежурству — отдельный этап с чек-листом и парным дежурством. Метрики при этом не собираются вообще, и единственным аргументом остаётся «мне тяжело», который проигрывает любому числу.
  • Компенсация деньгами вместо изменения системы. Доплата — это признание цены, а не её устранение. Если она становится способом не чинить причины, вы просто выкупили право будить людей.

Мини-итог

  • Дежурство — контракт из трёх частей: покрытие, время отклика, полномочия. Без третьей части первые две не работают: дежурный без права откатить умеет только звонить дальше.
  • В неделе 168 часов: 45 рабочих, 74 нерабочих бодрствующих, 49 ночных. Оплачивают обычно 45, занята вся сетка. Ограничение действует и при нуле срабатываний.
  • Нагрузка определяется делителем. Ротация из трёх при 10 страницах в неделю даёт 51 ночное пробуждение в год на человека, ротация из десяти — 15. Первый ход при перегрузке — увеличить делитель, а не терпеть лучше.
  • Схема primary + secondary не удваивает страницы, но удваивает часы ограничения: в команде из шести каждый под пейджером треть года.
  • SLO 99,9 % — это 43,2 минуты в месяц. Разобранный ночной инцидент с одной эскалацией стоит 27 минут, то есть 62 % бюджета; два таких инцидента исчерпывают месяц полностью. Из 27 минут 19 (70 %) — разбуженный человек.
  • Таймаут эскалации — параметр с ценником: 5 минут = 11,6 % месячного бюджета. Начиная примерно с 99,95 % человек в контуре не успевает арифметически, и SLO обязана защищать автоматика.
  • Эскалацию по таймауту и эскалацию по запросу нельзя смешивать: первая — сбой процесса, вторая — его корректная работа. Ноль эскалаций по запросу означает, что помощь звать боятся.
  • Ночью действуют только обратимые действия: откат, флаг, деградация. Обоснование измеримое: на восемнадцатом часу бодрствования психомоторные показатели соответствуют 0,05 % алкоголя в крови, а субъективно человек этого не замечает.
  • Круглосуточное двухэшелонное покрытие одного сервиса стоит порядка 85 000 USD в год при полной стоимости инженера 120 000 USD — сопоставимо со ставкой ещё одного человека. Отказ платить не устраняет цену, а переносит её в текучесть.
  • Эффекты связаны усиливающими контурами с задержкой в месяцы: шум → усталость → длиннее инциденты → нет времени на правки → шум. Разрывать нужно в одной точке и жёстко; самая короткая петля — «правки по итогам инцидентов не попадают в спринт». Главная метрика для разговора наверх при этом — число прерванных ночей за квартал: её нельзя переформулировать так, чтобы она перестала звучать тревожно.
  • Часть проблем не имеет технического решения: делитель, компенсация, сила политики бюджета ошибок. Инженерная работа здесь — сделать цену видимой в часах и деньгах и зафиксировать её в постмортемах наравне с техническими причинами.
  • Из практики Google берите механизмы, а не нормативы: ранбуки, передача, полномочия, безвинная эскалация переносятся бесплатно; ротации из 12–16 человек на сервис и отдельные роли — нет.

Источники

Что дальше

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

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

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

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

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

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