Перейти к содержанию

Оптимизация запросов


Запросы — узкое горлышко дашборда. Медленный запрос → дашборд тормозит → человек теряет терпение и уходит. Оптимизация запросов — инвестиция в надёжность себя самого в 3 часа ночи.


Prometheus / PromQL

  1. Всегда фильтруйте. {job="api"} вместо голого http_requests_total.
  2. Избегайте кардинальности. by (user_id) с миллионами уникальных id — смерть Prometheus'у. Используйте topk(5, ...).
  3. Используйте Recording Rules для больших досок. Вместо сложного запроса histogram_quantile(0.99, rate(...)) предвычислите через recording rule: - record: job:api:latency_99pct и полегчает.
  4. Не используйте offset без крайней нужды. Этот оператор виртуально удваивает запросы.
  5. Не ставьте неограниченные диапазоны. $__range — полезно, но для большого окна в 7 дней это может означать "покажи мне всё". Prometheus это не пережуёт. Ограничь верхним пределом.


Loki / LogQL

  1. Label filters first. Loki индексирует метки, а не содержимое. Поэтому {job="api"} |= "error" — быстро, а |= "error" — медленно.
  2. json | line_format. Разбирайте JSON внутри логов — так вы получаете поля и к ним можно применять фильтры без regexp.
  3. Время имеет значение. {job="api"} запрос на временной диапазон 5 минут — ок, на 7 дней без агрегации — не делайте.


SQL-базы

  1. Используйте временные индексы. Убедитесь, что created_at или timestamp — проиндексированы в БД. Иначе каждый запрос дашборда — full scan таблицы.
  2. Макросы времени Grafana. $__timeFilter(created_at) — автоматически подставляет WHERE по времени.
  3. Лимитируйте количество записей. LIMIT 1000 — дашборда с 10 000 строками смотреть неудобно.


Макросы и шаблоны времени

Всегда используйте:

$__timeFilter(...)
$__interval
$__rate_interval

Они подстраиваются под zoom и разрешение вашего дисплея. Например, $__interval будет 30s при просмотре 1h и может стать 5m при просмотре 1 week — Grafana сама подстраивает, чтобы поместилось в разрешение экрана. Не пишите фиксированное [5m].


Практический пример

Плохо:

rate(node_network_transmit_bytes_total{device!="lo"}[5m])

Хорошо:

rate(node_network_transmit_bytes_total{device!~"lo|docker.*|veth.*"}[$__rate_interval])



Далее: Стандартизация