3. Alerting и алерты

Правила оповещений: от шума к действию

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

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

Здесь вступает в силу ключевая дисциплина Observability — Алертинг (Alerting).

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


От шума к действию

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

Если проблему можно решить перезапуском пода — этим должен заниматься Kubernetes. Если диск заполняется медленно и места хватит еще на две недели — об этом создается тикет в трекере задач в рабочий день. Но если выгорает бюджет ошибок и клиенты интернет-магазина не могут завершить платеж — звенит боевой алерт.


Архитектура Алертинга в Prometheus

В экосистеме Prometheus алертинг разделен на две независимые части. Это классический пример разделения ответственности (Separation of Concerns).

flowchart LR
    A["Prometheus Server"] -->|"1 - Evaluate Rules<br>Каждые N секунд"| B["Alert Rules"]
    B -->|"2 - Fire Alert<br>Active State"| C["Alertmanager"]

    subgraph D ["Alertmanager Duties"]
        C --> E["Deduplication<br>Дедупликация"]
        E --> F["Grouping<br>Группировка"]
        F --> G["Routing<br>Маршрутизация"]
        G --> H["Notify<br>Slack/Email/PagerDuty"]
    end

    style A fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#fff
    style C fill:#881337,stroke:#f43f5e,stroke-width:2px,color:#fff
    style D fill:#0f172a,stroke:#475569,stroke-width:1px,color:#fff
  

1. Prometheus Server (Detection)

Сам Prometheus занимается только вычислениями. Он раз в минуту (по умолчанию) прогоняет ваши PromQL запросы.

  • Если условие истинно (например, up == 0), он переводит алерт в состояние Pending (Ожидание).
  • Если условие истинно в течение времени for (например, 5 минут), он переводит алерт в состояние Firing (Стрельба) и отправляет его в Alertmanager.

Prometheus оперирует конечным автоматом состояний: Inactive -> Pending -> Firing.

2. Alertmanager (Notification)

Alertmanager — это отдельный бинарный файл (тоже написан на Go). Он не умеет считать метрики. Он умеет управлять потоками уведомлений.

  • Deduplication: Если Prometheus отправит 100 одинаковых алертов (с одной меткой), Alertmanager отправит в Slack только одно сообщение. Он объединяет события от нескольких реплик Prometheus через протокол сплетен (Gossip Protocol на базе HashiCorp memberlist).
  • Grouping: Если упало 100 сервисов одновременно (например, проблема в сети дата-центра), Alertmanager склеит их в одно сообщение, а не завалит вас спамом.
  • Routing: Разные алерты направляются в разные каналы в зависимости от лейблов (критичные — дежурным в PagerDuty, предупреждения — в Slack команды).
  • Silencing: Возможность временно выключить алерт (например, на время планового обслуживания).

Mechanical Sympathy: Цена алертинга

Алертинг не бесплатен для Prometheus.
Каждое правило алертинга — это запрос к базе данных TSDB.

  • Если у вас сложный запрос с rate() и большими окнами, он нагружает CPU Prometheus.
  • Если правил тысячи, Prometheus может не успевать их вычислить.

Best Practice: Не используйте слишком маленькие окна for.

  • for: 10s — почти бессмысленно, так как один «провал» в скрейпинге может вызвать ложный алерт.
  • for: 5m — стандарт индустрии. Это фильтрует кратковременные выбросы (flapping).

Параметр for: 5m заставляет Prometheus выждать пять минут непрерывного выполнения аварийного условия в статусе Pending, прежде чем переводить его в Firing.


Anatomy of a Good Alert (Анатомия хорошего алерта)

Хороший алерт отвечает на три вопроса:

  1. What? Что сломалось? (Имя алерта и лейблы).
  2. Where? Где сломалось? (Instance, Job).
  3. So What? Насколько это критично? (Severity: Critical/Warning).

Пример плохого алерта:

YAML
# ПЛОХО
alert: HighCPU
expr: process_cpu_seconds_total > 0.8
  • Не понятно, это 80% или 0.8 секунд?
  • Нет контекста. Может, сервис просто обрабатывает нагрузку.

Пример хорошего алерта (Go Specific):

YAML
# ХОРОШО
alert: GoServiceHighGoroutines
expr: go_goroutines{job="my-go-service"} > 10000
for: 5m
labels:
  severity: warning
annotations:
  summary: "High Goroutine count on {{ $labels.instance }}"
  description: "Instance {{ $labels.instance }} has {{ $value }} goroutines. Potential leak."

Специфика Go: Что нужно мониторить обязательно?

Для Go-бэкендов есть набор специфичных метрик, которые должны быть в алертах.

  1. Goroutine Leak:
    go_goroutines > 10000 (или линейный рост).
    Это самый частый баг в Go. Если горутин растет и не падает — приложение скоро упадет с OOM или перестанет отвечать.

  2. GC Pressure:
    rate(go_gc_duration_seconds_sum[5m]) > 10.
    Если GC запускается слишком часто, это значит, что приложение генерирует слишком много мусора. Это «тормозит» реальную работу (Stop-The-World pauses).

  3. SLO Violations:
    Мы обсуждали SLO. Алерт должен срабатывать, когда Error Budget выгорает быстрее, чем мы готовы принять.
    Используйте Multi-window, Multi-burn-rate Alerts (стандарт Google SRE).

    • Пример: Если за последний час потрачено 5% месячного бюджета — PagerDuty (Critical).
    • Если за последние 3 дня потрачено 10% бюджета — Ticket (Warning).

Итог

  1. Prometheus вычисляет правила, Alertmanager отправляет уведомления.
  2. Алерты должны быть Actionable (требовать действия). Если действие не нужно — это график, а не алерт.
  3. Используйте for clause, чтобы избежать шума (flapping).
  4. В Go обязательно следите за go_goroutines и go_gc_duration_seconds.

В следующей статье мы поговорим о главной проблеме алертинга — как отделить сигнал от шума: 4. Noise vs signal.