Что такое rate() и зачем он нужен?
Функция rate()
в PromQL необходима для вычисления средней скорости изменения метрики в секунду за определённый период времени. Она часто используется для мониторинга таких показателей, как:
Частота запросов к серверу (RPS),
Загрузка CPU,
Количество ошибок и др.
Это один из самых распространённых инструментов для анализа трендов в метриках.
Расчёт SLO с использованием rate() и sum()
Один из частых кейсов использования rate()
— расчёт SLI (Service Level Indicator) и проверка соответствия SLO (Service Level Objective).
В книге Google SRE предлагается следующая формула оценки доступности:
> Доступность = (количество успешных запросов) / (общее количество запросов)
В Prometheus-терминах она выглядит так:
sum(rate(http_requests_total{status!~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
Объяснение формулы:
http_requests_total{status!~"5.."}
— количество успешных запросов (т.е. без кодов 5xx).http_requests_total
— общее количество запросов.sum()
агрегирует данные по всем инстансам и другим лейблам.
Если появляются ошибки 5xx, значение метрики падает ниже 1. Это легко встроить в оповещения.
Пример alert’а в Prometheus:
groups:
- name: SLOAlerts
rules:
- alert: HighErrorRate
expr: sum(rate(http_requests_total{status!~"5.."}[5m])) / sum(rate(http_requests_total[5m])) < 0.99
for: 10m
labels:
severity: warning
annotations:
summary: "Высокий уровень ошибок: доступность ниже 99%"
Пример расчета общего количество запросов в секунду (RPS):
sum(rate(http_requests_total[$__rate_interval]))
Топ-5 эндпоинтов по ошибкам 5xx:
topk(5, sum by (path) (rate(http_requests_total{status=~"5.."}[$__rate_interval])))
Какой диапазон использовать с rate()?
Диапазон в
rate()
должен быть как минимум в 4 раза больше интервала опроса (scrape interval).Для построения графиков в Grafana раньше использовали переменную
$__interval
для задания этого диапазона.
Рассмотрим пример запроса:
rate(prometheus_tsdb_head_samples_appended_total[$__interval])
На первый взгляд — всё хорошо. Но если мы уменьшим временной диапазон с 2 дней до 1 часа, может внезапно появиться надпись «No data».
Почему? Потому что $__interval
стал слишком коротким и нарушил первое правило: rate()
просто не может корректно отработать с одной точкой. Например, если $__interval
стал 15s, а ваш scrape interval тоже 15s, то нужно минимум 1m, чтобы запрос работал корректно.
Решение — указать диапазон вручную:
rate(prometheus_tsdb_head_samples_appended_total[1m])
Но это неудобно:
– нужно задавать Min step
вручную для каждой панели
– это ограничивает разрешение, с которым Grafana делает запросы в Prometheus
Знакомьтесь: $__rate_interval
Чтобы всё «просто работало», появилась переменная $__rate_interval
. Она автоматически рассчитывает корректный диапазон rate()
на основе интервала опроса и масштаба графика.
Заменим в запросе $__interval
на $__rate_interval
:
rate(prometheus_tsdb_head_samples_appended_total[$__rate_interval])
Теперь график работает как ожидалось. Более того, появляется возможность видеть больше деталей благодаря плавному скользящему среднему.
💡 Совет: если вы всё же хотите сгладить график — просто установите Min interval
в 1 минуту в настройках запроса.
Как работает $__rate_interval
$__rate_interval
всегда будет как минимум в 4 раза больше интервала опроса. Но откуда Grafana узнаёт ваш scrape interval?
Prometheus сам знает только текущий интервал опроса, но не сохраняет его в истории. Grafana берёт значение из настроек источника данных (Prometheus datasource). Там есть поле Scrape interval
.
Рекомендуется использовать единый интервал опроса для всех метрик в организации и прописать его в настройках. По умолчанию — 15s. Если какие-то метрики используют другой интервал — можно задать Min step
вручную для соответствующей панели.
⚠️ Обратите внимание:
Min interval
, который задаётся в панели Grafana, не влияет на вычисление$__rate_interval
. Он влияет только на разрешение отображаемого графика.
Медленно изменяющиеся счётчики и rate()
Рассмотрим пример: prometheus_tsdb_head_truncations_total
— это счётчик усечений в Prometheus, который увеличивается каждые 2 часа.
Если вы используете:
rate(prometheus_tsdb_head_truncations_total[$__interval])
то с большой вероятностью не увидите ничего, особенно на коротком интервале. Замените на:
rate(prometheus_tsdb_head_truncations_total[$__rate_interval])
И вы получите ожидаемый график.
Заключение
Используйте
rate()
для анализа производительности и ошибок в системе.Всегда агрегируйте данные с помощью
sum()
при расчётах SLO.Применяйте
$__rate_interval
, чтобы ваши графики и алерты всегда корректно работали.Учитывайте интервал опроса при построении запросов.