Моніторинг з Prometheus і Grafana: метрики, PromQL і алерти, які не дратують
Як влаштований Prometheus, які метрики збирати в першу чергу (RED і USE), базовий PromQL і правила для алертів, на які справді хочеться реагувати.
Моніторинг потрібен, щоб дізнаватися про проблеми раніше за користувачів і швидко знаходити причину. Prometheus — стандарт де-факто для метрик у світі контейнерів і Kubernetes, а Grafana — для їх візуалізації.
Як працює Prometheus
Prometheus сам приходить по метрики: раз на 15–30 секунд робить HTTP-запит на /metrics кожної цілі (pull-модель) і зберігає часові ряди у своїй базі.
# Так виглядає ендпоінт /metrics
http_requests_total{method="GET",route="/api/orders",status="200"} 18421
http_requests_total{method="GET",route="/api/orders",status="500"} 37
http_request_duration_seconds_bucket{route="/api/orders",le="0.1"} 16890
http_request_duration_seconds_bucket{route="/api/orders",le="0.5"} 18302Чотири типи метрик:
| Тип | Що це | Приклад |
|---|---|---|
| Counter | Лише зростає (скидається при рестарті) | кількість запитів, помилок |
| Gauge | Може рости і падати | пам'ять, довжина черги, з'єднання |
| Histogram | Розподіл значень по «кошиках» | час відповіді |
| Summary | Перцентилі, пораховані на клієнті | рідко потрібен, краще histogram |
УвагаНе кладіть у мітки значення з необмеженою кількістю варіантів:
user_id,/orders/:id), а не реальний шлях.
Що вимірювати: RED і USE
RED — для сервісів (з точки зору користувача):
- Rate — запитів за секунду;
- Errors — частка помилок;
- Duration — час відповіді (перцентилі).
USE — для ресурсів (CPU, диск, мережа, пули з'єднань):
- Utilization — наскільки зайнятий;
- Saturation — черга, що не встигає обробитись;
- Errors — помилки ресурсу.
PromQL: п'ять запитів, які потрібні щодня
# 1. Запитів за секунду по сервісу (за останні 5 хвилин)
sum by (service) (rate(http_requests_total[5m]))
# 2. Частка помилок 5xx
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
# 3. p95 часу відповіді з гістограми
histogram_quantile(0.95,
sum by (le, route) (rate(http_request_duration_seconds_bucket[5m])))
# 4. Використання пам'яті контейнерами відносно ліміту
sum by (pod) (container_memory_working_set_bytes{container!=""})
/ sum by (pod) (kube_pod_container_resource_limits{resource="memory"})
# 5. Диск закінчиться протягом 24 годин (за поточним трендом)
predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 24 * 3600) < 0ПорадаДо counter завжди застосовуйте
rate()абоincrease(). Саме значення лічильника (18421 запит з моменту старту) майже нічого не означає і «падає» до нуля після кожного рестарту.
Алерти: на симптоми, а не на причини
Погані алерти будять людей через те, що ні на що не впливає: «CPU 85% на вузлі 7». Хороші — коли страждають користувачі або ось-ось почнуть.
groups:
- name: api
rules:
- alert: ApiHighErrorRate
expr: |
sum(rate(http_requests_total{service="api",status=~"5.."}[5m]))
/ sum(rate(http_requests_total{service="api"}[5m])) > 0.02
for: 5m
labels:
severity: page
annotations:
summary: "API: понад 2% помилок 5xx протягом 5 хвилин"
runbook: "https://wiki.example.com/runbooks/api-errors"
- alert: DiskWillFillIn24h
expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 86400) < 0
for: 30m
labels:
severity: ticketПравила хорошого алерту:
for:— умова має триматися кілька хвилин, щоб не реагувати на одиночні сплески;- severity:
page(будити вночі) лише для того, що зачіпає користувачів зараз; решта —ticket; - runbook у кожному алерті: що перевірити і що робити;
- регулярний перегляд: алерт, на який ніхто не реагував місяць, — видалити або переробити.
ВажливоЯкщо черговий отримує 30 алертів за ніч, він перестає їх читати. Утома від алертів (alert fatigue) — головна причина, чому реальні інциденти пропускають.
SLO замість порогів «на око»
Ще кращий підхід — алертити на витрату бюджету помилок. Наприклад, SLO «99.9% запитів успішні за 30 днів» дає бюджет 0.1%. Алерт спрацьовує, коли бюджет витрачається занадто швидко: за годину згоріло 2% місячного бюджету — це сторінка черговому, за 6 годин 5% — тікет.
Дашборди в Grafana
Дашборд сервісу варто будувати зверху вниз:
- Верхній ряд — RED: запити, помилки, p50/p95/p99.
- Далі — залежності: БД, кеш, черги, зовнішні API.
- Внизу — ресурси: CPU, пам'ять, рестарти подів.
Зберігайте дашборди як код (JSON у Git або провіжинінг Grafana) — інакше після чергового «покращення» ніхто не знайде, як було.
Чому погано додавати мітку user_id до метрики http_requests_total?
Кожне унікальне значення мітки створює окремий часовий ряд. З тисячами або мільйонами користувачів кількість рядів вибухає (high cardinality), Prometheus з'їдає пам'ять і сповільнюється. Деталі на рівні окремого користувача — задача логів і трейсів, а не метрик.
Збережіть статтю собі
Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.
Увійти через Google Інші способи входу