Дежурство: расписание, эскалация и цена для людей
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. Работающее определение:
Дежурство — это оплаченное обязательство отреагировать на сигнал за фиксированное время, обладая заранее выданными полномочиями что-то сделать.
Три части, и все три обязательны:
- Покрытие. Какие часы, какие сервисы, какие классы сигналов. «Круглосуточно» — не покрытие, а лозунг: если в команде четыре человека, круглосуточно означает конкретное расписание с конкретной ценой, и её нужно назвать.
- Время отклика. Сколько минут от доставки уведомления до подтверждения (ack) и сколько — до первого содержательного действия. Числа не берутся из вежливости, они выводятся из бюджета ошибок; ниже посчитаем.
- Полномочия. Что дежурный имеет право сделать сам, без чьего-либо разрешения. Это самый часто пропускаемый пункт и самый дорогой: без него любая эскалация превращается в поиск того, кто разрешит.
Уберите третий пункт — и первые два бессмысленны. Дежурный с временем отклика в пять минут и без права откатить релиз просто быстрее начнёт кому-то звонить.
Есть и четвёртая, неявная часть контракта — обязательства работодателя: компенсация, право не выйти утром после ночного инцидента, право поменяться сменой. Если их нет, контракт односторонний, и его цена всё равно будет уплачена — только текучестью, а не деньгами.
Арифметика покрытия: сколько людей нужно на 168 часов
В неделе 7 × 24 = 168 часов. Разложим их с точки зрения дежурного, у которого рабочий день с 10:00 до 19:00 в будни:
| Зона | Как считается | Часов в неделю |
|---|---|---|
| Рабочие часы | 5 дней × 9 часов | 45 |
| Вне работы, но бодрствую | 168 − 45 − 49 | 74 |
| Ночь, 00:00–07:00 | 7 дней × 7 часов | 49 |
| Всего | 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 минуты в месяц. Это весь допустимый простой за месяц: меньше сорока пяти минут.
Теперь разберём один ночной инцидент по минутам.
в другой комнате P->>A: t=6, повторный звонок P->>B: t=9, таймаут 5 минут, эскалация B->>P: t=11, ack B->>B: t=17, встал, ноутбук, VPN, дашборд B->>M: t=23, гипотеза подтверждена по трейсам B->>L: t=24, нужен доступ к консоли провайдера L-->>B: t=25, доступ выдан B->>M: t=27, откат релиза, ошибки прекратились Note over M,L: 27 минут — это 62 % месячного бюджета при SLO 99,9 %
Разложение по источникам задержки:
| Отрезок | Минут | Кто «тратит» | Чем сокращается |
|---|---|---|---|
| Окно правила до срабатывания | 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 в год
Полсотни строк кода, которые превращают спор «дежурство у нас тяжёлое или нормальное» в разговор про числа. Держите этот файл в репозитории команды и пересчитывайте раз в квартал: он показывает не абсолютную истину, а направление изменений.
Петля, которая раскручивается сама
Отдельные эффекты — шум, усталость, уход людей — связаны не последовательно, а кольцами. И кольца эти усиливающие: каждое прохождение делает следующее хуже.
страницы"] --> TIRED["Истощение
и цинизм"] TIRED --> SLOW["Дольше ack,
хуже решения"] SLOW --> LONG["Инциденты
длятся дольше"] LONG --> BUDGET["Бюджет ошибок
сгорает"] BUDGET --> FREEZE["Заморозка,
аврал, переработки"] FREEZE --> TIRED TIRED --> QUIT["Люди уходят
из ротации"] QUIT --> FEWER["Меньше людей
на те же 168 часов"] FEWER --> OFTEN["Каждый дежурит
чаще"] OFTEN --> TIRED LONG --> NOFIX["Нет времени
на первопричины"] NOFIX --> NOISE
Здесь ровно три усиливающих контура, и каждый из них сам себя подпитывает:
шум → усталость → медленнее реакция → длиннее инциденты → нет времени на правки → шум;усталость → уходы → меньше делитель → чаще дежурства → усталость;длиннее инциденты → сгорает бюджет → заморозка и аврал → усталость → длиннее инциденты.
Это тот же класс явлений, что и каскадный отказ в распределённой системе: положительная обратная связь плюс задержка. Разница лишь в том, что в контуре стоят люди, а постоянная времени измеряется месяцами, а не секундами, — поэтому связь между «мы полгода терпели шумные алерты» и «за квартал уволились двое» никто не замечает. Механику задержек и усиливающих контуров подробно разбирают главы про петли обратной связи и про задержки; в 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 человек на сервис и отдельные роли — нет.
Источники
- Google. Site Reliability Engineering, ch. 11: Being On-Call — канонический текст, включая норматив по числу инцидентов на смену и обоснование через время на постмортем.
- Google. The Site Reliability Workbook, ch. 8: On-Call — практические схемы ротаций, разбор нескольких реальных конфигураций.
- PagerDuty. Incident Response: Being On-Call — открытая внутренняя практика: чек-листы, передача смены, ожидания от дежурного.
- Atlassian. On-call: guide and best practices — схемы расписаний и компенсации.
- Charity Majors. On Call Shouldn’t Suck: A Guide For Managers — про то, как дежурство ломается организационно и что с этим делает руководитель.
- Increment. On-Call issue — сборник практик из разных компаний, полезен как контраргумент к «все делают как Google».
- Van Dongen H. et al. The cumulative cost of additional wakefulness. Sleep, 26(2), 2003 — накопленный дефицит и неспособность его заметить.
- Dawson D., Reid K. Fatigue, alcohol and performance impairment. Nature 388, 235 (1997).
- Landrigan C. et al. Effect of Reducing Interns’ Work Hours on Serious Medical Errors in Intensive Care Units. NEJM 351:1838–1848, 2004.
- Maslach C., Schaufeli W., Leiter M. Job Burnout. Annual Review of Psychology, 52, 2001 — три компонента выгорания, в том числе цинизм как защитная реакция.
- Karasek R. Job Demands, Job Decision Latitude, and Mental Strain. Administrative Science Quarterly, 24(2), 1979 — модель «требования и контроль».
- Boushey H., Glynn S. There Are Significant Business Costs to Replacing Employees. Center for American Progress, 2012.
- Смежные главы портала: выгорание, компенсация и переговоры о ней, наблюдаемость и дежурство в DevOps-треке, стратегии выката.
Что дальше
Мы разобрали, кто дежурит, по какому расписанию, что происходит при молчании и во что это обходится в часах, минутах бюджета и деньгах. Осталось главное: телефон уже зазвонил, вы уже за ноутбуком — что делать в первые пятнадцать минут, кто за что отвечает, если людей больше одного, и как вести связь так, чтобы расследование не превратилось в чат из двухсот сообщений.