Alertmanager 0.15: многоуровневый routing и silence management - как мы победили alert fatigue
Настроили routing в Alertmanager 0.15: критические алерты - в PagerDuty, предупреждения - по командам в Slack, ночные - только SMS. Alert fatigue снизился заметно.
Prometheus Alertmanager 0.15 - улучшенный routing и silence management для крупных инсталляций
Когда мы переезжали на Prometheus 2.3 в июле, в том же посте упомянули Alertmanager 0.15 как «отдельный разговор». Разговор состоялся - и оказался длиннее, чем казалось.
Исходная ситуация была классическая: один Alertmanager на несколько проектов, один канал в Slack куда летело всё подряд, дежурные давно научились не читать уведомления. Это называется alert fatigue, и лечится оно не дополнительными алертами, а правильной маршрутизацией.
Что изменилось в 0.15
Alertmanager 0.15 вышел вместе с Prometheus 2.3. Принципиальных изменений два: переработанный движок routing и новый API для silence management.
Routing в предыдущих версиях был, но работал плоховато при сложных деревьях: матчинг по нескольким лейблам со вложенными маршрутами часто давал неожиданные результаты, и разобраться почему конкретный алерт ушёл не туда было нетривиально. В 0.15 ввели continue: true как нормальный флаг (раньше оно тоже было, но документация была мягко говоря скудной) и починили приоритет матчинга в поддеревьях.
Silence management теперь через API v2, который отдаёт JSON с нормальной схемой. Раньше силенсы создавались только через веб-интерфейс или curl с кривым форматом; теперь их можно автоматизировать: создать силенс на окно планового обслуживания скриптом из CI/CD - это реально работает без боли.
Как мы это раскатали
На managed-проектах у нас к этому моменту было три характерных класса алертов, которые вели себя совсем по-разному.
Первый - критические события: упал pod в production, кончилось место на диске, недоступен эндпойнт. Дежурный должен проснуться, даже если час ночи. Сюда - PagerDuty, звонок, SMS.
Второй - предупреждения: загрузка CPU выше 70% больше пяти минут, медленные запросы в базу, диск занят на 80%. Это информация для команды, которая работает прямо сейчас. Сюда - Slack в канал команды, в рабочее время.
Третий - информационный шум: успешные деплои, ротация сертификатов, плановые рестарты. Это нужно видеть, но не срочно. Сюда - отдельный Slack-канал, который читают по желанию.
Конфиг routing вырос примерно до такого дерева:
route:
receiver: 'slack-ops-default'
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: 'pagerduty-oncall'
continue: true
- match:
severity: critical
receiver: 'slack-ops-critical'
- match:
severity: warning
receiver: 'slack-team-routing'
routes:
- match:
team: backend
receiver: 'slack-backend'
- match:
team: infra
receiver: 'slack-infra'
- match:
severity: info
receiver: 'slack-ops-info'
group_wait: 10m
group_interval: 30m
Ключевой момент с continue: true на критических: алерт идёт в PagerDuty И в Slack одновременно. Без continue он останавливался бы на первом совпавшем маршруте, и команда бы ничего не видела в Slack - только дежурный получал звонок.
Лейблы - главная боль
Вся эта схема работает ровно настолько хорошо, насколько аккуратно расставлены лейблы в правилах алертов. Когда мы начали расставлять team: и severity: по всем правилам, обнаружилось что часть правил вообще без severity написана - просто alert: SomethingBad и всё. Это исторический хлам, накопившийся пока Alertmanager был простым.
Пришлось пройтись по всем rule-файлам и проставить лейблы явно. Заодно выяснилось что несколько алертов дублировались: один и тот же признак проверялся в двух разных файлах с немного разными порогами. Это классика при росте инфраструктуры без централизованного владения правилами.
Силенсы во время деплоев
Второй большой выигрыш - автоматические силенсы при деплоях. Раньше при плановом обновлении компонента дежурный либо вручную закрывал силенс через веб-интерфейс, либо просто игнорировал шквал алертов в процессе. Оба варианта плохие: первый забывают сделать, второй тренирует людей игнорировать алерты.
Через API v2 мы добавили в деплой-скрипт создание силенса на время обновления:
curl -s -X POST \
http://alertmanager:9093/api/v2/silences \
-H 'Content-Type: application/json' \
-d '{
"matchers": [
{"name": "service", "value": "'"$SERVICE"'", "isRegex": false}
],
"startsAt": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
"endsAt": "'"$(date -u -d '+30 minutes' +%Y-%m-%dT%H:%M:%SZ)"'",
"createdBy": "deploy-script",
"comment": "Planned deploy of '"$SERVICE"' '"$VERSION"'"
}'
Тридцать минут с автоматическим истечением. Если деплой затянулся - деплой-скрипт может продлить силенс, если нет - он просто истечёт сам. Это не идеально (всё ещё нужна интеграция с CI/CD), но уже в разы лучше ручного режима.
Что по итогу
Субъективно - количество алертов, которые команды реально читают и реагируют на них, выросло. Количество жалоб в духе «опять Slack завалило» - упало. Точные цифры мы не мерили намеренно: слишком много переменных менялось одновременно, чтобы атрибутировать эффект именно Alertmanager.
Нерешённая проблема: routing-конфиг превращается в священный документ, который никто не трогает из страха сломать. Тест routing до деплоя - через amtool check-routes - помогает, но не полностью. Хочется что-то вроде юнит-тестов для маршрутизации, но пока это делается руками: берёшь пример алерта, прогоняешь через amtool config routes test, смотришь куда пошёл.
Следующий шаг - поставить amtool в CI и валидировать конфиг при каждом мерже. Это скорее организационная задача, чем техническая.
- Prometheus 2.3: мигрировали с 1.x на 2.x - новая TSDB и WAL меняют картину · 11 июля 2018
- Grafana 5.2: дашборды и datasource в Git - мониторинг как код · 27 августа 2018