Почему статические пороги не работают

Наивный подход к мониторингу заключается в настройке статических порогов — например, оповещение при превышении 1% ошибок в течение пяти минут. Это тот подход, который мы рассматривали ранее в статье Prometheus vs Zabbix.

- alert: HighErrorRate
  expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.01
  for: 5m

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

Концепция Burn Rate: расчет расхода Error Budget

Практика Google SRE предлагает более гибкий подход: настраивать алерты не на абсолютную долю ошибок, а на скорость расходования бюджета ошибок (Error Budget). Мы используем два временных окна: короткое (для фиксации резких сбоев) и длинное (для выявления плавной деградации).

# Быстрый burn: за 1 час тратим бюджет в 14.4 раза быстрее
# устойчивого темпа — при таком темпе весь месячный бюджет
# сгорит примерно за два дня. Точно достойно пейджа.
- alert: ErrorBudgetBurnFast
  expr: |
    (
      rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 14.4 * 0.001
    and
      rate(http_requests_total{status=~"5.."}[1h]) / rate(http_requests_total[1h]) > 14.4 * 0.001
    )
  labels:
    severity: page
 
# Медленный burn: за сутки тратим бюджет в 3 раза быстрее устойчивого
# темпа — недостаточно срочно для пейджа, но достаточно, чтобы
# завести тикет и разобраться до конца недели
- alert: ErrorBudgetBurnSlow
  expr: |
    (
      rate(http_requests_total{status=~"5.."}[6h]) / rate(http_requests_total[6h]) > 3 * 0.001
    and
      rate(http_requests_total{status=~"5.."}[1d]) / rate(http_requests_total[1d]) > 3 * 0.001
    )
  labels:
    severity: ticket

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

Правильная маршрутизация: не каждый алерт — критический

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

route:
  routes:
    - match:
        severity: page
      receiver: pagerduty-oncall
      repeat_interval: 15m
    - match:
        severity: ticket
      receiver: jira-backlog
      repeat_interval: 24h

Основной критерий для severity: page: «Может ли инженер сделать что-то прямо сейчас, чего нельзя отложить до утра?». Если ответ отрицательный, такой алерт должен попадать в систему тикетов.

Группировка уведомлений

Чтобы избежать «шторма алертов», когда один сбой вызывает каскад уведомлений, используйте механизм group_by. Это позволяет сгруппировать связанные события в одно информативное сообщение.

route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 30s      # подождать полминуты, вдруг придут связанные алерты
  group_interval: 5m   # не слать новую группу чаще раза в 5 минут
  repeat_interval: 4h  # не повторять один и тот же несработавший алерт чаще