Коротко:
- Усталость от уведомлений возникает не из-за количества метрик, а из-за плохо настроенной маршрутизации и отсутствия дедупликации.
- Первый шаг - аудит: посмотреть, сколько сработавших правил за последние 30 дней не привели ни к одному действию дежурного.
- Grouping и inhibition rules в Alertmanager убирают большую часть шума без изменения самих правил Prometheus.
- В PagerDuty дедупликация работает через Event Rules и Service-level deduplication key - без этого каждый повтор создает новый инцидент.
- Качество on-call мониторинга измеряется не количеством алертов, а долей тех, что потребовали реального действия.
Откуда берется шум
Представьте: дежурный получает 40 уведомлений за ночь. Из них 35 - это один и тот же упавший под, который Kubernetes перезапустил через 10 секунд. Три - предупреждения о высоком CPU, которые ушли сами. Одно - реальная проблема с базой данных. И одно - тест, который кто-то забыл отключить.
Через неделю такого режима дежурный начинает игнорировать уведомления. Не потому что ленится, а потому что мозг адаптируется к сигналам, которые не требуют действия. Это и есть alert fatigue - состояние, при котором важный инцидент тонет в потоке незначимых срабатываний.
Проблема почти никогда не в самих правилах Prometheus. Правила могут быть написаны корректно. Проблема в том, что между метрикой и звонком дежурному нет ни одного фильтра: нет группировки, нет подавления зависимых сигналов, нет дедупликации на уровне PagerDuty.
Аудит перед настройкой: что смотреть
Прежде чем что-то менять, нужно понять, где именно теряется качество. Хороший способ - выгрузить историю срабатываний за последние 30 дней и посмотреть на три вещи.
Actionability rate - доля уведомлений, после которых дежурный что-то сделал. Если она ниже 50%, система генерирует больше шума, чем сигнала. В здоровой системе этот показатель должен быть выше 80%.
Топ повторяющихся правил. Обычно 20% правил дают 80% срабатываний. Именно с ними нужно работать в первую очередь - либо поднять порог, либо добавить for-задержку, либо настроить inhibition.
Время до первого действия. Если дежурный в среднем реагирует через 20 минут после получения уведомления, это сигнал: либо уведомления приходят ночью и человек не успевает, либо он перестал доверять системе и проверяет, не уйдет ли само.
Эти данные можно получить из Alertmanager API (/api/v2/alerts) или из истории инцидентов в PagerDuty через Analytics раздел.
Настройка алертов Prometheus: for, labels и severity
Большинство ложных срабатываний можно убрать еще на уровне правил, не трогая Alertmanager.
Параметр for задает минимальную продолжительность состояния до отправки уведомления. Без него правило срабатывает на любой кратковременный всплеск.
- alert: HighCPU
expr: rate(container_cpu_usage_seconds_total[5m]) > 0.9
for: 10m
labels:
severity: warning
annotations:
summary: "CPU выше 90% на {{ $labels.pod }}"Десять минут - разумный порог для предупреждения о CPU. Если проблема ушла сама за 9 минут, дежурный не получит ничего. Для критических ситуаций - например, сервис полностью недоступен - for: 1m или даже for: 30s оправданы.
Метки severity и team - не просто документация. Они управляют маршрутизацией в Alertmanager. Если все правила имеют одинаковый severity или вообще не имеют его, routing tree работает вхолостую.
Хорошая практика - три уровня: critical (будит ночью), warning (приходит в Slack, не звонит), info (только в дашборд, без уведомлений). Большинство команд используют два уровня и отправляют все в PagerDuty - отсюда и шум.
Alertmanager routing: дерево маршрутов без хаоса
Alertmanager получает все сигналы от Prometheus и решает: кому отправить, когда, в каком виде и нужно ли вообще. Ключевые механизмы - это route, group_by, inhibit_rules и receivers.
Группировка
Без группировки каждое срабатывание - отдельное сообщение. С группировкой Alertmanager собирает похожие события в один пакет и отправляет их вместе.
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'slack-warnings'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
group_wait: 10sgroup_wait - сколько ждать перед первой отправкой, чтобы собрать связанные события. group_interval - как часто отправлять обновления по уже открытой группе. repeat_interval - через сколько повторить, если проблема не решена.
Параметр repeat_interval: 4h для предупреждений - разумный минимум. Если его не выставить или оставить значение по умолчанию (1h), дежурный будет получать одно и то же каждый час.
Inhibition rules
Это один из самых недооцененных инструментов. Inhibition позволяет подавить одни уведомления, если уже активно другое - более высокоуровневое.
Классический пример: нода упала. Prometheus начинает генерировать десятки сигналов - недоступны поды, растет latency, падают health checks. Но все это - следствие одного события. Если настроить inhibition, дежурный получит только один сигнал: нода недоступна.
inhibit_rules:
- source_match:
severity: 'critical'
alertname: 'NodeDown'
target_match:
severity: 'warning'
equal: ['cluster', 'node']Здесь: если активен NodeDown с severity: critical для конкретного узла, все предупреждения с тем же cluster и node подавляются. Дежурный видит одну проблему вместо двадцати.
Inhibition работает только для активных алертов - как только источник разрешится, подавленные снова станут видимы. Это важно: ничего не теряется, просто приоритизируется.
Маршрутизация по команде
Если несколько команд используют один Prometheus, имеет смысл разделить маршруты по метке team. Тогда backend-команда не получает уведомления о проблемах с фронтом, и наоборот.
routes:
- match:
team: backend
receiver: 'pagerduty-backend'
- match:
team: frontend
receiver: 'slack-frontend'
- match:
team: infra
receiver: 'pagerduty-infra'Это снижает шум для каждой конкретной команды и повышает релевантность: дежурный видит только то, за что отвечает.
PagerDuty дедупликация: как не плодить инциденты
Даже при хорошо настроенном Alertmanager PagerDuty может создавать дублирующие инциденты, если не настроена дедупликация на его стороне.
PagerDuty использует поле dedup_key (в Events API v2) для определения, является ли событие новым инцидентом или обновлением существующего. Если Alertmanager отправляет одно и то же событие несколько раз без явного dedup_key, каждый раз создается новый инцидент.
При интеграции через Alertmanager receiver для PagerDuty dedup_key формируется автоматически на основе группы алертов. Но если вы используете прямую интеграцию или вебхуки, нужно явно задавать ключ:
{
"routing_key": "YOUR_INTEGRATION_KEY",
"dedup_key": "prod-payment-service-high-error-rate",
"event_action": "trigger",
"payload": {
"summary": "Error rate выше 5% на payment-service",
"severity": "critical",
"source": "prometheus"
}
}Хороший dedup_key - это детерминированная строка, которая одинакова для всех повторов одной и той же проблемы. Обычно это комбинация имени сервиса, типа проблемы и окружения: prod-payment-high-error-rate.
Event Rules в PagerDuty
Event Rules (в новом интерфейсе - Event Orchestration) позволяют фильтровать и трансформировать события до создания инцидента. Это второй рубеж фильтрации после Alertmanager.
Что можно сделать через Event Rules:
- Подавить события с определенными метками в нерабочее время (например, предупреждения о медленных фоновых задачах).
- Понизить severity для известных нестабильных сервисов во время планового обслуживания.
- Направить события в нужный сервис на основе содержимого payload.
- Автоматически добавить runbook-ссылку к инциденту.
Это особенно полезно, когда несколько источников (Prometheus, Datadog, CloudWatch) отправляют события в один PagerDuty аккаунт - правила позволяют нормализовать их без изменения каждого источника отдельно.
Silence и maintenance windows
Плановые работы - отдельная причина шума. Если команда деплоит в пятницу вечером и не выставляет silence, дежурный получает поток уведомлений о нормальных перезапусках подов.
В Alertmanager silence создается через UI или API:
amtool silence add \
alertname="PodRestarting" \
namespace="production" \
--duration=2h \
--comment="Плановый деплой payment-service"В PagerDuty аналогичный механизм - Maintenance Windows. Их можно создавать заранее и привязывать к конкретным сервисам. Во время окна инциденты создаются, но не эскалируются и не будят дежурного.
Хорошая практика - добавить создание silence в CI/CD пайплайн. Перед деплоем пайплайн автоматически выставляет silence на 30 минут для затронутых сервисов. После успешного деплоя silence снимается.
Типичные ошибки при настройке
| Ошибка | Последствие | Как исправить |
|---|---|---|
Нет параметра for в правилах | Срабатывание на любой кратковременный всплеск | Добавить for: 5m или for: 10m для предупреждений |
Все правила с severity: critical | Дежурный не может приоритизировать | Ввести три уровня и отправлять в PagerDuty только critical |
| Нет inhibition rules | Одна проблема генерирует десятки уведомлений | Настроить подавление зависимых сигналов |
repeat_interval не выставлен или слишком мал | Одно и то же уведомление каждый час | Установить repeat_interval: 4h для warning, 2h для critical |
| Нет dedup_key в PagerDuty | Каждый повтор создает новый инцидент | Задать детерминированный dedup_key на основе сервиса и типа проблемы |
| Silence не используется при деплоях | Шум во время плановых работ | Автоматизировать создание silence в CI/CD |
Метрики качества on-call мониторинга
Настройка - это не разовое действие. Нужно регулярно смотреть на несколько показателей, чтобы понимать, улучшается ли ситуация.
Actionability rate - главная метрика. Считается как отношение инцидентов, где дежурный выполнил хоть какое-то действие, к общему числу уведомлений. Цель - выше 80%.
Mean time to acknowledge (MTTA) - среднее время до подтверждения инцидента. Если оно растет, дежурный либо перегружен, либо перестал доверять системе.
Noise ratio - доля уведомлений, которые разрешились сами без вмешательства. Хорошее значение - ниже 10%. Если выше - нужно пересматривать пороги или добавлять задержки.
Pages per shift - количество ночных звонков за одно дежурство. Более трех звонков за ночь - это уже серьезная нагрузка, которая влияет на качество работы на следующий день.
Все эти метрики можно собрать из PagerDuty Analytics или построить дашборд в Grafana на основе данных Alertmanager.
Чеклист: что проверить перед следующим дежурством
- Все правила Prometheus имеют параметр
forс разумным значением. - Используются три уровня severity, в PagerDuty попадает только critical.
- Настроены inhibition rules для зависимых сигналов (нода, кластер, база данных).
- Выставлены
group_by,group_waitиrepeat_intervalв Alertmanager. - В PagerDuty настроен dedup_key для всех интеграций.
- Есть процедура создания silence при плановых деплоях.
- Настроены Event Rules или Event Orchestration в PagerDuty для фильтрации второго уровня.
- Команда регулярно (раз в месяц) проводит ревью правил и удаляет неактивные или неинформативные.
- Actionability rate отслеживается и видна в дашборде.
- Каждый новый алерт проходит ревью: что именно он должен сообщить дежурному и что тот должен сделать.
Как проверить правило до того, как оно попадет в продакшен
Одна из причин накопления шума - правила добавляются без проверки реального поведения. Инженер пишет выражение, смотрит, что оно синтаксически корректно, и отправляет в репозиторий. Через неделю выясняется, что правило срабатывает каждые 15 минут на нормальный трафик.
Перед тем как добавить новое правило, стоит пройти три шага.
Шаг 1: проверить выражение в Prometheus UI. Вкладка Graph показывает, как менялось значение метрики за последние часы или дни. Если выражение уже сейчас возвращает ненулевое значение на стабильной системе, порог выбран неверно.
Шаг 2: оценить частоту исторических пересечений порога. Если за последние 7 дней условие выполнялось 50 раз, а инцидентов было 2, правило будет генерировать шум. Нужно либо поднять порог, либо увеличить for.
Шаг 3: сформулировать runbook до публикации. Если нельзя ответить на вопрос «что именно должен сделать дежурный, получив это уведомление», правило не готово. Уведомление без понятного действия - это шум по определению.
Этот процесс можно формализовать через шаблон pull request для изменений в правилах: поле «ожидаемая частота срабатываний» и поле «действие дежурного» делают ревью быстрее и снижают риск добавления проблемных правил.
Разница между симптомным и причинным подходом к правилам
Большинство команд пишут правила на уровне причин: CPU выше порога, память заканчивается, диск заполнен. Это удобно, потому что метрики очевидны. Но такой подход дает много шума: причины могут меняться без влияния на пользователей.
Симптомный подход фокусируется на том, что видит пользователь: высокая задержка, рост ошибок, недоступность эндпоинта. Правила на уровне симптомов срабатывают реже, но каждое срабатывание действительно требует внимания.
| Тип правила | Пример | Частота ложных срабатываний | Когда использовать |
|---|---|---|---|
| Причинное | CPU выше 90% | Высокая | Для capacity planning, не для on-call |
| Причинное | Диск заполнен на 85% | Средняя | Предупреждение заранее, не критичный звонок |
| Симптомное | HTTP 5xx выше 1% за 5 минут | Низкая | Основной сигнал для дежурного |
| Симптомное | p99 latency выше 2 секунд | Низкая | Основной сигнал для дежурного |
| Симптомное | Сервис недоступен более 30 секунд | Очень низкая | Критичный звонок ночью |
Хорошая система мониторинга строится так: симптомные правила будят дежурного, причинные правила помогают разобраться в причине уже после того, как инцидент открыт. Причинные метрики - это инструмент диагностики, а не триггер для звонка.
Практический ориентир: если правило срабатывает, но пользователи ничего не замечают, это правило не должно попадать в PagerDuty. Переместите его в Slack или только в дашборд. Оставьте ночные звонки для ситуаций, которые реально влияют на работу сервиса прямо сейчас.
Работа с унаследованными правилами: как разобрать накопленный долг
Во многих командах правила копились годами. Кто-то добавил правило под конкретный инцидент, потом забыл удалить. Кто-то скопировал набор из открытого репозитория и не адаптировал под свою систему. В итоге в конфигурации десятки правил, половина из которых никто не понимает.
Разбирать такой долг проще поэтапно, а не за один раз.
Первый этап: инвентаризация. Выгрузить все активные правила и для каждого проверить: когда последний раз срабатывало, есть ли у него annotations с описанием и runbook, есть ли owner - метка команды или сервиса.
Второй этап: категоризация. Разделить правила на три группы: активно используемые и понятные, активные но без понятного действия, давно не срабатывавшие. Третья группа - первые кандидаты на удаление или перевод в silent режим.
Третий этап: постепенная чистка. Не удалять сразу - сначала перевести подозрительные правила в severity: info и наблюдать две недели. Если никто не заметил отсутствия уведомлений, правило можно убирать.
Важно договориться внутри команды: каждое новое правило добавляется с явным owner и датой ревью. Это не бюрократия, а способ не накапливать новый долг, пока разбираете старый.