Модуль: Observability · Уровень: Middle+/Senior
TL;DR#
Grafana — слой визуализации и алертинга поверх множества источников данных (Prometheus, Loki, Tempo, и др.). Дашборд = набор panels, каждая панель выполняет запрос к data source и рендерит результат (time series, stat, gauge, table, heatmap). Сила Grafana — корреляция трёх сигналов: из метрики (Prometheus) по exemplar прыгнуть в трейс (Tempo), из трейса в логи (Loki) через derived fields. Templating ($variable) делает дашборды переиспользуемыми между сервисами/инстансами. Grafana Unified Alerting — отдельная подсистема (alert rules → notification policies → contact points), не путать с панельным «алертом». Senior-практика: дашборды как код (provisioning/Terraform/Grafonnet, не клики), иерархия overview → service → instance, аннотации деплоев, и осторожность с $__rate_interval, downsampling и вводящими в заблуждение average-панелями.
Теория#
Источники данных и корреляция#
| Data source | Сигнал | Язык запросов |
|---|---|---|
| Prometheus / Mimir | Метрики | PromQL |
| Loki | Логи | LogQL |
| Tempo | Трейсы | TraceQL |
| Postgres/MySQL, CloudWatch, Elasticsearch | разное | SQL/нативный |
Главная ценность — переходы между сигналами в одном UI:
- Exemplars (Prometheus): точки на графике латенси несут
trace_id→ клик → трейс в Tempo. - Trace-to-logs (Tempo): из спана прыжок в Loki по
trace_id. - Derived fields (Loki): регуляркой выдёргиваем
trace_idиз строки лога → кнопка «открыть трейс».
Это и есть «observability», а не три разрозненных инструмента.
Типы панелей#
| Панель | Когда |
|---|---|
| Time series | Основная: тренды rate/latency/errors во времени |
| Stat | Одно число: текущий error budget, RPS, версия |
| Gauge | Значение относительно порога (utilization, SLO остаток) |
| Table | Топ-N (по эндпоинтам, по подам), instant запросы |
| Heatmap | Визуализация гистограммы во времени (распределение латенси) — нужен histogram data source |
| Histogram | Распределение значений (не во времени) |
| Logs / Traces | Панели для Loki/Tempo |
| Bar gauge / State timeline | Статусы, up/down |
Heatmap — лучший способ увидеть бимодальность латенси, которую average и даже p99 скрывают.
Templating / переменные#
$job — Query variable: label_values(up, job)
$instance — label_values(up{job="$job"}, instance) (зависимый)
$interval — Interval variable: 1m,5m,1h# Панель использует переменные
sum by (le) (rate(http_request_duration_seconds_bucket{job="$job", instance=~"$instance"}[$__rate_interval]))- Query variables — значения из лейблов (
label_values(...)), каскадно зависимые. - Multi-value +
=~"$instance"— выбор нескольких значений (регэксп-матч). - Repeat panels/rows — одна панель размножается по каждому значению переменной (по инстансу/поду).
- Custom/Interval/Textbox/Datasource переменные — для гибкости и мульти-кластерных дашбордов.
Transformations#
Постобработка результатов на стороне Grafana без изменения запроса: join нескольких queries, organize/rename fields, calculate (добавить вычисляемое поле), group by, filter, reduce. Полезно для table-панелей и комбинирования источников.
Dashboards as code#
Кликами собранный дашборд не версионируется и не воспроизводится. Senior-подход:
// provisioning/dashboards/payments.json (упрощённо)
{
"title": "Payments / RED",
"templating": { "list": [{ "name": "job", "query": "label_values(up, job)" }] },
"panels": [
{ "type": "timeseries", "title": "Rate",
"targets": [{ "expr": "sum(rate(http_requests_total{job=\"$job\"}[$__rate_interval]))" }] }
]
}# provisioning/dashboards/provider.yaml — Grafana подхватывает из папки
apiVersion: 1
providers:
- name: 'gitops'
folder: 'Services'
type: file
options: { path: /etc/grafana/dashboards }Варианты: file provisioning, Grafonnet (Jsonnet-библиотека для генерации JSON), Terraform provider (grafana_dashboard), хранение JSON в git с code review. Это даёт воспроизводимость, ревью, откат.
Grafana Alerting (Unified)#
Современный alerting — отдельная подсистема, единая для всех data sources:
- Alert rule — запрос (PromQL/LogQL/…) + условие +
for(как долго держится) → состояния Normal/Pending/Firing. - Contact points — куда слать (Slack, PagerDuty, email, webhook).
- Notification policies — дерево маршрутизации по лейблам алерта (label matching), с grouping (схлопывание похожих в одно уведомление), таймингами (
group_wait,repeat_interval). - Silences — временное глушение по матчерам (на время maintenance).
- Mute timings — расписания без уведомлений.
Отличие от legacy alerting: старый был привязан к панели (один алерт = одна панель, только Prometheus-подобные источники). Unified — независимые rule groups, мульти-источники, multi-dimensional (один rule → много алертов по сериям).
Важно: «алерт на панели» в UI ≠ настоящий alert rule. Для прода — alert rules + notification policies, либо вообще Prometheus Alertmanager (Grafana может им рулить).
Что показывать#
Иерархия дашбордов (drill-down):
- Overview / fleet — health всех сервисов, золотые сигналы агрегатом, SLO/error budget.
- Service dashboard — RED (Rate/Errors/Duration) для конкретного сервиса + зависимости.
- Instance/pod — USE (CPU/mem/saturation), GC, goroutines, для дебага конкретного инстанса.
Best practices:
- На каждый сервис — стандартный RED-дашборд (генерируй из шаблона).
- Латенси — перцентили (p50/p90/p99), не average; heatmap для распределения.
- Аннотации деплоев (vertical lines) — мгновенно видно «сломалось после релиза».
- Consistent time ranges и единые единицы.
- Не перегружать: 6–12 осмысленных панелей лучше 40 шумных.
Подводные камни / gotchas#
- Дашборды кликами не версионируются — без provisioning/git теряются и не воспроизводятся.
$__intervalvs$__rate_interval:$__intervalзависит от ширины графика и может стать меньше scrape interval →rate()даёт дыры/нули. Дляrate()всегда$__rate_interval(учитывает scrape interval).max data pointsи downsampling: Grafana просит у источника ограниченное число точек; при широком окне точки агрегируются и скрывают пики (max-spike сглаживается). Для алерт-валидации смотри сырьё.- Heatmap требует правильного формата: histogram-метрика с бакетами и правильный режим панели, иначе каша.
- Алерт на панели ≠ alert rule — панельная индикация не шлёт уведомления через notification policies.
- Misleading average panel:
avg(latency)или mean легко рисует «всё хорошо», пряча хвост; ревьюверы дашбордов это ловят. - Перегруженный дашборд + много панелей → тормоза браузера и когнитивная перегрузка дежурного.
- Перцентиль из готовых summary-квантилей (если источник — summary) нельзя агрегировать в панели по инстансам — рисует неправду.
- Variables с
Allи regex могут раздуть запрос и положить Prometheus тяжёлым PromQL.
Вопросы на собеседовании#
В: В чём разница $__interval и $__rate_interval и почему это важно?
О: $__interval вычисляется из ширины панели и max data points, может оказаться меньше scrape interval, тогда rate() не находит ≥2 точек в окне и рисует дыры. $__rate_interval гарантирует окно ≥ ~4× scrape interval, поэтому для rate()/increase() нужно использовать его. Это та же проблема «правила 4×» из Prometheus, но на стороне Grafana.
В: Как организовать корреляцию метрик, трейсов и логов в Grafana? О: Exemplars в Prometheus-метриках несут trace_id → клик с графика латенси открывает трейс в Tempo; в Tempo trace-to-logs ведёт в Loki по trace_id; в Loki derived fields выдёргивают trace_id из строки лога и дают кнопку в Tempo. Так в одном UI идёшь metric → trace → log, что и есть смысл observability.
В: Почему дашборды надо хранить как код? О: Кликами собранные дашборды не версионируются, не ревьюятся и не воспроизводятся при пересоздании Grafana. Provisioning из git (JSON/Grafonnet/Terraform) даёт code review, откат, единые шаблоны на все сервисы и устойчивость к потере инстанса. Это GitOps-подход к observability.
В: Чем Unified Alerting отличается от legacy и от Prometheus Alertmanager? О: Legacy alerting привязан к панели (один алерт = одна панель, ограниченные источники). Unified — независимые rule groups для любых data sources, multi-dimensional (один rule → много алертов по сериям), с notification policies и contact points. Prometheus Alertmanager делает маршрутизацию/дедуп/группировку на стороне Prometheus; Grafana Unified может его дублировать или управлять им — выбор зависит от того, где живёт источник истины алертов.
В: Почему стат-панель с average latency опасна? О: Среднее скрывает хвост распределения и чувствительно к выбросам; при бимодальном трафике mean может лежать в «пустой» зоне между двумя пиками и показывать «всё хорошо», когда часть пользователей страдает. Нужны перцентили (p99) и heatmap распределения.
В: Что показывать на дашборде сервиса? О: RED: Rate (RPS), Errors (доля 5xx/бизнес-ошибок), Duration (p50/p90/p99 + heatmap). Плюс зависимости (latency/errors downstream), saturation ресурсов (USE), SLO/error budget, и аннотации деплоев. Иерархия overview → service → instance для drill-down.
В: Как сделать один дашборд для всех инстансов сервиса?
О: Query variables: $job = label_values(up, job), зависимый $instance = label_values(up{job="$job"}, instance), multi-value с =~"$instance" в запросах. Опционально repeat панелей по инстансу. Это шаблонизирует дашборд под любой сервис/под без копипасты.
На что копают на senior+#
- Dashboards-as-code / GitOps: Grafonnet/Terraform/provisioning, генерация стандартных RED-дашбордов из библиотек, версионирование и ревью.
- Механика
$__rate_intervalи взаимодействие с scrape interval, max data points и downsampling — почему графики «врут» при больших окнах. - Корреляция трёх сигналов в UI (exemplars, trace-to-logs, derived fields) и как это настраивается на уровне data sources.
- Архитектура алертинга: Grafana Unified vs Prometheus Alertmanager, где источник истины, multiwindow burn-rate алерты, дедуп при HA-паре Prometheus.
- Масштабирование и multi-tenancy: организация дашбордов/папок, RBAC, datasource per tenant, производительность при сотнях дашбордов/панелей.
- Provisioning безопасности: read-only provisioned дашборды, секреты data sources, service accounts вместо API keys.