Grafana Alerting + Telegram: как мы настроили умные оповещения для e-commerce «МаркетЛайн» и перестали пропускать аварии

Ситуация: дашборды есть, оповещений нет

E-commerce «МаркетЛайн» обратился к нам в itfresh.ru после серии инцидентов: за последний квартал магазин терял от 200 до 800 тысяч рублей за каждый простой, потому что никто не узнавал о проблеме вовремя. Дежурный инженер проверял Grafana-дашборды вручную раз в час, а ночью мониторинг отсутствовал полностью.

Инфраструктура:

  • Grafana 10.3 — 18 дашбордов (только визуализация, алертов нет)
  • Prometheus — сбор метрик с 12 серверов и 8 микросервисов
  • Alertmanager — установлен, но не настроен (default конфиг)
  • Telegram — команда общается в рабочем чате, но алертов туда не приходит

Три инцидента, которые подтолкнули к обращению:

  1. Падение PostgreSQL в 3 часа ночи — обнаружено в 9 утра, потеря 6 часов заказов
  2. Redis OOM — корзины перестали работать, обнаружено через 40 минут по жалобам в поддержку
  3. Nginx 502 — backend-сервер ушёл в swap, обнаружено клиентом, а не командой

Задача: выстроить полноценную систему оповещений с маршрутизацией в Telegram, email и Slack — с учётом рабочего/нерабочего времени, severity и минимумом ложных срабатываний.

Unified Alerting в Grafana 10+: архитектура

Начиная с Grafana 9, старая система алертов (Legacy Alerting) заменена на Unified Alerting. Это встроенный Alertmanager внутри Grafana, который поддерживает полную совместимость с Prometheus alerting rules, но управляется через GUI.

Архитектура Unified Alerting состоит из четырёх компонентов:

  • Alert rules — правила, описывающие условие срабатывания (PromQL, LogQL или SQL-запрос к data source)
  • Contact points — каналы доставки (Telegram, email, Slack, PagerDuty, webhooks)
  • Notification policies — маршрутизация алертов: какой алерт в какой канал, группировка, повторы
  • Silences / Mute timings — подавление алертов на время плановых работ

Мы сразу отключили legacy alerting и включили unified в grafana.ini:

# /etc/grafana/grafana.ini
[unified_alerting]
enabled = true

[alerting]
enabled = false

# Интервал оценки правил (по умолчанию 10s, для нашего объёма достаточно)
[unified_alerting]
evaluation_timeout = 30s
min_interval = 10s

# Встроенный Alertmanager — используем его, внешний не нужен
[unified_alerting.alertmanager]
# Если нужен внешний Alertmanager:
# forwarding_rules = /etc/grafana/alertmanager-forwarding.yaml

Преимущество unified alerting: все алерты управляются в одном месте через Grafana UI или API. Не нужно отдельно редактировать YAML-файлы Alertmanager и rules в Prometheus — всё в одном интерфейсе.

Alert rules: PromQL-правила с multi-condition логикой

Для «МаркетЛайн» мы создали 24 alert rules, разбитых на 5 групп (folders в Grafana). Ключевой принцип — каждое правило проверяет не одну метрику, а комбинацию условий, чтобы снизить ложные срабатывания.

Пример: алерт на высокий error rate — срабатывает только если одновременно растёт процент ошибок И есть достаточный трафик (чтобы 1 ошибка из 2 запросов не дала 50% error rate):

# Alert rule: High Error Rate (multi-condition)
# Condition A — error rate выше 5%
A: sum(rate(http_requests_total{status=~"5.."}[5m]))
   /
   sum(rate(http_requests_total[5m]))
   > 0.05

# Condition B — трафик достаточный (более 10 rps)
B: sum(rate(http_requests_total[5m])) > 10

# Итоговое условие: A AND B
# В Grafana UI это настраивается через Math expression:
C: $A AND $B

Алерт на заканчивающееся место на диске с предсказанием:

# Alert rule: Disk Space Prediction
# Condition A — текущее заполнение > 75%
A: (1 - node_filesystem_avail_bytes{mountpoint="/"}
       / node_filesystem_size_bytes{mountpoint="/"}) > 0.75

# Condition B — при текущей скорости заполнения место кончится менее чем за 24 часа
B: predict_linear(
     node_filesystem_avail_bytes{mountpoint="/"}[6h], 24*3600
   ) < 0

# Итоговое условие: диск заполнен И скоро кончится
C: $A AND $B

Для каждого правила мы задали evaluation interval (как часто проверять) и pending period (сколько держать условие перед срабатыванием):

  • Critical — eval каждые 10s, pending 1m (быстрая реакция)
  • Warning — eval каждые 30s, pending 5m (фильтрация кратковременных всплесков)
  • Info — eval каждые 1m, pending 10m (только устойчивые тренды)

Также мы настроили recording rules для тяжёлых PromQL-выражений, которые вычисляются заранее и хранятся как отдельные метрики:

# recording_rules.yml в Prometheus
groups:
  - name: marketline_recording
    interval: 30s
    rules:
      - record: job:http_requests:error_rate_5m
        expr: |
          sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
          /
          sum by (job) (rate(http_requests_total[5m]))

      - record: job:http_requests:latency_p99_5m
        expr: |
          histogram_quantile(0.99,
            sum by (job, le) (rate(http_request_duration_seconds_bucket[5m]))
          )

      - record: instance:node_cpu:utilization_5m
        expr: |
          1 - avg by (instance) (
            rate(node_cpu_seconds_total{mode="idle"}[5m])
          )

Recording rules снижают нагрузку на Prometheus при оценке alert rules — вместо пересчёта тяжёлого запроса каждые 10 секунд, Grafana просто читает готовую метрику.

Contact points: Telegram-бот, email и Slack

Contact point — это канал, куда Grafana отправляет уведомление. Мы настроили три канала:

1. Telegram-бот. Создали бота через @BotFather, добавили его в группу мониторинга. Настройка через Grafana UI: Alerting → Contact points → New contact point.

# Получение chat_id для группы:
# 1. Добавить бота в группу
# 2. Отправить любое сообщение в группу
# 3. Вызвать API:
curl -s "https://api.telegram.org/bot/getUpdates" | jq '.result[-1].message.chat.id'
# Для группы chat_id будет отрицательным: -1001234567890

# Настройка contact point в Grafana (через Provisioning YAML):
apiVersion: 1
contactPoints:
  - orgId: 1
    name: telegram-critical
    receivers:
      - uid: tg-critical-1
        type: telegram
        settings:
          bottoken: "7123456789:AAF..."
          chatid: "-1001234567890"
          parse_mode: HTML
          disable_web_page_preview: true
          message: |
            {{ template "telegram.default" . }}

  - orgId: 1
    name: telegram-warning
    receivers:
      - uid: tg-warning-1
        type: telegram
        settings:
          bottoken: "7123456789:AAF..."
          chatid: "-1009876543210"
          parse_mode: HTML
          disable_web_page_preview: true

2. Email — для отчётов и алертов, которые не требуют мгновенной реакции:

# grafana.ini — настройка SMTP
[smtp]
enabled = true
host = smtp.yandex.ru:465
user = alerts@marketline.ru
password = "$__file{/etc/grafana/smtp_password}"
from_address = alerts@marketline.ru
from_name = Grafana MarketLine
startTLS_policy = NoStartTLS
# Для порта 465 используем SSL, не STARTTLS

3. Slack — для команды разработки (отдельный канал #dev-alerts):

# Contact point: Slack через Incoming Webhook
apiVersion: 1
contactPoints:
  - orgId: 1
    name: slack-dev
    receivers:
      - uid: slack-dev-1
        type: slack
        settings:
          url: "https://hooks.slack.com/services/T.../B.../xxx"
          recipient: "#dev-alerts"
          username: "Grafana Bot"
          icon_emoji: ":rotating_light:"
          mentionChannel: "here"
          title: |
            {{ template "slack.default.title" . }}
          text: |
            {{ template "slack.default.text" . }}

Каждый contact point мы протестировали кнопкой «Test» в Grafana UI перед включением в production. Telegram — самый надёжный канал: сообщения доходят даже при нестабильном интернете благодаря retry-механизму.

Notification policies: маршрутизация по severity и времени

Notification policy определяет, какой алерт куда отправлять. Это дерево правил с наследованием — дочерние политики перекрывают родительские.

Наша структура для «МаркетЛайн»:

# notification-policies.yaml (Grafana Provisioning)
apiVersion: 1
policies:
  - orgId: 1
    receiver: telegram-warning  # default receiver
    group_by:
      - alertname
      - instance
    group_wait: 30s       # Ждём 30s перед отправкой (группировка)
    group_interval: 5m    # Минимум 5m между повторными группами
    repeat_interval: 4h   # Повтор нерешённого алерта каждые 4 часа
    routes:
      # Critical — мгновенно в Telegram + email
      - receiver: telegram-critical
        matchers:
          - severity = critical
        group_wait: 10s
        group_interval: 1m
        repeat_interval: 30m
        continue: true  # продолжить проверку — отправить ещё и в email

      - receiver: email-oncall
        matchers:
          - severity = critical
        group_wait: 10s
        repeat_interval: 1h
        continue: false

      # Warning — в Telegram с задержкой
      - receiver: telegram-warning
        matchers:
          - severity = warning
        group_wait: 1m
        repeat_interval: 4h
        continue: false

      # Dev-алерты (application-level) — только в Slack
      - receiver: slack-dev
        matchers:
          - team = dev
        group_wait: 2m
        repeat_interval: 8h
        continue: false

Ключевые настройки, которые спасают от alert fatigue:

  • group_by — группирует алерты по alertname и instance. Если 5 дисков одновременно заполнились, придёт одно сообщение с 5 алертами, а не 5 отдельных
  • group_wait — ждёт 30 секунд, собирая все алерты, прежде чем отправить. Предотвращает шквал сообщений при массовом сбое
  • repeat_interval — не дублирует одно и то же уведомление чаще, чем раз в N времени
  • continue: true — позволяет отправить алерт в несколько каналов (Telegram И email), иначе маршрутизация останавливается на первом совпадении

Silence, mute timings и шаблоны сообщений

Silence — временное подавление конкретных алертов. Используем при плановых работах:

# Создание silence через API (полезно для автоматизации через CI/CD)
curl -X POST http://grafana.internal/api/alertmanager/grafana/api/v2/silences \
  -H "Authorization: Bearer $GRAFANA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "matchers": [
      {"name": "instance", "value": "db-master-01", "isRegex": false}
    ],
    "startsAt": "2026-04-05T22:00:00Z",
    "endsAt": "2026-04-06T02:00:00Z",
    "createdBy": "deploy-pipeline",
    "comment": "Плановое обновление PostgreSQL 16.2 -> 16.3"
  }'

Mute timings — расписание подавления алертов (повторяющееся). Например, не беспокоить ночью warning-алертами:

# mute-timings.yaml
apiVersion: 1
muteTimes:
  - orgId: 1
    name: nighttime-warnings
    time_intervals:
      - times:
          - start_time: "23:00"
            end_time: "07:00"
        weekdays:
          - monday:friday
        location: Europe/Moscow

Mute timing привязывается к notification policy — warning-алерты ночью подавляются, critical по-прежнему приходят в любое время.

Alert templates — кастомизация сообщений через Go templates. Мы написали свой шаблон для Telegram, чтобы сообщения были компактными и информативными:

# alert-templates.yaml
apiVersion: 1
templates:
  - orgId: 1
    name: telegram_custom
    template: |
      {{ define "telegram.marketline" }}
      {{ if eq .Status "firing" }}🔴{{ else }}🟢{{ end }} {{ .Status | toUpper }}
      {{ range .Alerts }}
      {{ .Labels.alertname }}
      Severity: {{ .Labels.severity }}
      Instance: {{ .Labels.instance }}
      {{ if .Annotations.summary }}📋 {{ .Annotations.summary }}{{ end }}
      {{ if .Annotations.description }}📝 {{ .Annotations.description }}{{ end }}
      {{ if .Annotations.runbook_url }}📖 Runbook{{ end }}
      {{ if .Values }}Current: {{ range $k, $v := .Values }}{{ $k }}={{ $v }} {{ end }}{{ end }}
      Started: {{ .StartsAt.Format "02.01.2006 15:04 MSK" }}
      {{ if eq $.Status "resolved" }}Resolved: {{ .EndsAt.Format "02.01.2006 15:04 MSK" }}{{ end }}
      ---
      {{ end }}
      {{ end }}

Шаблон поддерживает: цветовую индикацию (firing/resolved), ссылку на runbook, текущие значения метрик и время начала/окончания инцидента. Всё в одном компактном сообщении Telegram.

Best practices: борьба с alert fatigue

Alert fatigue — главная причина, почему команды начинают игнорировать алерты. У «МаркетЛайн» до нас было 0 алертов, но мы видели проекты, где 200 алертов в день приводили к тому же результату — никто не реагирует.

Наши правила, внедрённые для «МаркетЛайн»:

1. Каждый алерт требует действия. Если на алерт нечего делать (информационный) — это не алерт, а дашборд. Мы убрали все «FYI»-алерты.

2. Три уровня severity, не больше:

  • critical — требует немедленного вмешательства (подъём ночью)
  • warning — требует внимания в рабочее время
  • info — отправляется только в Slack/email, не в Telegram

3. Pending period — обязателен. Алерт не должен срабатывать на 10-секундный всплеск CPU:

# Плохо: срабатывает на любой всплеск
- alert: HighCPU
  expr: instance:node_cpu:utilization_5m > 0.9
  for: 0s  # мгновенно

# Хорошо: только устойчивая нагрузка
- alert: HighCPU
  expr: instance:node_cpu:utilization_5m > 0.9
  for: 5m  # 5 минут подряд

4. Hysteresis. Порог срабатывания и порог разрешения должны отличаться, чтобы алерт не мигал:

# Диск: алерт при 85%, разрешение при 75%
# В Grafana это делается через два условия:
# Firing: disk_used_percent > 85
# Resolved: disk_used_percent < 75 (через отдельное правило с keep_firing_for)

5. Runbook для каждого critical-алерта. Ссылка в аннотациях обязательна. Дежурный инженер в 3 часа ночи не должен гадать, что делать.

6. Еженедельный review алертов. Раз в неделю смотрим: какие алерты срабатывали, сколько было ложных, какие нужно подкрутить. Это 15 минут, которые экономят часы.

Результаты и выводы

Через месяц после внедрения Grafana Alerting для «МаркетЛайн»:

МетрикаДоПосле
Время обнаружения инцидента (MTTD)40 мин — 6 часов1-3 мин
Время реакции (MTTR)2-3 часа15-30 мин
Пропущенных инцидентов за месяц3-50
Ложных срабатываний в неделю0 (алертов не было)2-3
Каналов оповещения03 (Telegram, email, Slack)
Active alert rules024

Первый инцидент после внедрения — падение connection pool в PostgreSQL в субботу утром — был обнаружен через 90 секунд. Дежурный увидел Telegram-сообщение с ссылкой на runbook, выполнил перезапуск pgbouncer и восстановил сервис за 8 минут. До внедрения этот инцидент стоил бы 4-5 часов простоя.

Grafana Unified Alerting — мощный инструмент, который заменяет отдельный Alertmanager для большинства команд. Ключевое — не количество алертов, а их качество: каждый алерт должен быть actionable, иметь runbook и правильную маршрутизацию. Если вам нужна настройка мониторинга и оповещений — обращайтесь к нам в itfresh.ru.

Часто задаваемые вопросы

Для большинства случаев — нет. Grafana 10+ включает встроенный Alertmanager с полным функционалом: маршрутизация, группировка, silences, inhibition rules. Отдельный Alertmanager нужен, если у вас несколько Grafana-инстансов или вы хотите принимать алерты напрямую из Prometheus без прохода через Grafana.
Откройте @BotFather в Telegram, отправьте /newbot, задайте имя и username. Скопируйте токен. Добавьте бота в группу мониторинга. Отправьте сообщение в группу, затем вызовите https://api.telegram.org/bot/getUpdates — в ответе найдите chat.id (для группы он отрицательный). Эти два значения (токен и chat_id) укажите в contact point Grafana.
Для инфраструктуры из 10-20 серверов и 5-10 сервисов достаточно 15-30 правил. Главное правило: каждый алерт должен требовать действия. Если на алерт нечего делать — это не алерт, а элемент дашборда. Лучше 20 качественных алертов с runbooks, чем 200 шумящих.
Четыре ключевых приёма: 1) pending period — не реагировать на кратковременные всплески (for: 5m вместо for: 0s); 2) group_by — группировать однотипные алерты в одно сообщение; 3) mute timings — не беспокоить warning-алертами ночью; 4) еженедельный review — анализировать ложные срабатывания и корректировать пороги.
Да, через комбинацию mute timings и notification policies. Создайте mute timing для ночных часов (например, 23:00-07:00) и привяжите его к policy для warning-алертов. Critical-алерты будут приходить в Telegram круглосуточно, а warning — только в рабочее время. Можно также настроить ночные алерты в email вместо Telegram.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#Grafana alerting#Telegram оповещения#unified alerting#contact points#notification policies#alert rules#PromQL#mute timings
Комментарии 0

Оставить комментарий

загрузка...