Какие цели упали
Пусто — все цели отвечают. Почему цель не отвечает, пишет поле
lastError в API целей (prometheus).
Язык запросов к метрикам Prometheus: выбрать ряды по меткам, превратить счётчик в скорость, сложить и сравнить.
q() { promtool query instant http://localhost:9090 "$1"; }
q 'up'
1 — цель жива, 0 — нет
q 'up == 0'
только упавшие цели
q 'node_memory_MemAvailable_bytes'
ряды метрики по имени
q 'up{job="node"}'
ряды с нужной меткой
q 'rate(node_cpu_seconds_total[1m])'
счётчик → скорость
q 'increase(prometheus_http_requests_total[5m])'
прирост
q 'sum by (mode) (rate(node_cpu_seconds_total[1m]))'
сумма
q 'count by (job) (up)'
целей в каждом задании
PromQL — язык запросов Prometheus. Запрос выбирает временные ряды из базы Prometheus и считает по ним: скорость роста, сумму, долю, сравнение с порогом. На PromQL пишут выражения правил алертов (prometheus) и панели grafana.
Веб-интерфейс Prometheus на :9090 показывает результат графиком. Из
терминала запрос выполняет promtool из пакета prometheus:
Строка — один ряд: имя метрики, метки в фигурных скобках, после =>
— значение, после @ — метка времени в секундах unix-времени
(date -d @1792643816 переводит её в дату, см. date). Пустой
вывод с кодом 0 значит «таких рядов нет», это не ошибка.
Метрика — величина с именем: node_memory_MemAvailable_bytes —
доступная память в байтах. Метки — пары имя="значение", которые
уточняют, о чём число: mountpoint="/", cpu="0", mode="idle".
Имя вместе с полным набором меток задаёт временной ряд —
последовательность значений с метками времени. Сколько разных наборов
меток, столько рядов: node_filesystem_avail_bytes на учебной машине
— три ряда, для /, /boot и /boot/efi.
Метки job и instance добавляет сам Prometheus, когда собирает
метрики: job — имя задания из scrape_configs, instance — адрес
цели (prometheus).
Селектор выбирает ряды по имени и меткам:
Значение метки пишется в двойных кавычках. Регулярное выражение после
=~ должно совпасть со значением целиком: job=~"node" не выберет
node2, нужно job=~"node.*" (regex).
up — мгновенный вектор: по одному последнему значению каждого ряда.
Окно в квадратных скобках — up{job="node"}[1m] — даёт вектор за
интервал: все точки каждого ряда за последнюю минуту. При сборе раз в
15 секунд это четыре точки. Единицы окна — s, m, h, d.
Вектор за интервал сам по себе график не рисует: его передают
функции, которая сводит точки окна в одно число, — rate,
increase, avg_over_time, max_over_time.
Тип метрики виден в выводе экспортёра, строка # TYPE
(node-exporter):
| Тип | Как ведёт себя | Как читать |
|---|---|---|
counter |
только растёт с запуска процесса, при перезапуске — снова с нуля; имя обычно на _total |
через rate или increase |
gauge |
текущее значение, ходит вверх и вниз | как есть, сравнивать с порогом |
histogram |
ряды _bucket{le="…"}, _sum, _count: сколько наблюдений попало в каждую корзину |
_sum и _count — через rate |
Голое значение счётчика о нагрузке не говорит: 23.82 секунды простоя процессора с загрузки машины — неизвестно, много это или мало. Смысл есть у скорости его роста.
rate(счётчик[окно]) — средняя скорость роста за окно, в единицах в
секунду. increase(счётчик[окно]) — прирост за окно, то есть rate,
умноженный на длину окна.
Секунды процессора в секунду — доля времени: 0.9 у mode="idle"
значит, что ядро 90 % времени простаивало. Обе функции понимают сброс
счётчика: значение упало — процесс перезапустился, и рост считается от
нуля, без отрицательной скорости.
Окно должно вмещать хотя бы две точки, обычно берут четыре интервала
сбора: при scrape_interval: 15s — [1m]. [10s] при сборе раз в 15
секунд даёт пустой ответ. Пуст rate и в первые десятки секунд после
запуска Prometheus: второй точки ещё нет.
rate и increase — только для счётчиков. У gauge скорость роста
считают deriv, разницу за окно — delta, среднее и максимум —
avg_over_time и max_over_time.
sum, avg, min, max, count сводят ряды в один или в группы
по меткам:
После by (…) у результата остаются только перечисленные метки,
после without (…) — все, кроме перечисленных:
Сначала rate, потом sum: сумма счётчиков разных процессов
сбрасывается, когда перезапускается любой из них.
+ - * / между двумя наборами рядов считаются попарно — для рядов с
одинаковыми метками (имя метрики не в счёт). Число и ряд — для
каждого ряда:
После арифметики имени метрики у результата нет — только метки:
Сравнение >, <, >=, <=, ==, != работает как фильтр:
оставляет ряды, для которых условие верно, со своим значением, а
остальные убирает. Пустой ответ — условие не выполнено ни для одного
ряда. Со словом bool сравнение возвращает каждый ряд со значением
1 или 0:
% в PromQL — остаток от деления (7 % 3 — 1), процентов в языке
нет. «Меньше 10 %» пишут долей, < 0.1, или умножают долю на 100 и
сравнивают с 10. … * 100 < 10% не разбирается:
parse error: unexpected end of input.
Выражение правила алерта — такое же сравнение: алерт загорается для каждого ряда, который прошёл фильтр (prometheus).
Если наборы меток двух сторон различаются, пары не находятся и ответ
пуст: у node_filesystem_avail_bytes есть mountpoint, device,
fstype, у node_memory_MemTotal_bytes их нет. on (instance)
сравнивает только перечисленные метки, ignoring (…) — все, кроме
них. Если с одной стороны под пару подходят несколько рядов, нужен
group_left:
and, or, unless работают с наборами рядов: a unless b — ряды
a, для которых в b нет ряда с теми же метками. absent(…)
возвращает 1, когда рядов нет совсем: absent(up{job="app"}) — задания
app нет.
promtool query instant вычисляет выражение в один момент — сейчас.
promtool query range — в каждой точке периода с шагом --step, как
строит график Grafana:
То же через API — /api/v1/query и /api/v1/query_range. Выражение
передают через --data-urlencode: в нём фигурные скобки, кавычки и
пробелы. Значение в ответе — строкой, рядом с меткой времени:
Длинные строки вывода здесь перенесены. Значение числом
в jq — .value[1] | tonumber.
Пусто — все цели отвечают. Почему цель не отвечает, пишет поле
lastError в API целей (prometheus).
На учебной машине ответ — около 42: корень занят на 42 %. Для правила
«диск почти полон» добавь сравнение: … > 90.
avg by (instance) усредняет ядра машины: у машины с четырьмя ядрами
четыре ряда mode="idle", а нужно одно число на машину.
Имя метрики и метки зависят от приложения: найди их в его /metrics.
sum с обеих сторон убирает метки, и деление идёт число на число.
Возвращает 1, если рядов нет: задание удалили из конфига или в имени
опечатка. up == 0 такой случай не ловит — ряда up просто нет.
На учебной машине один node_exporter даёт около 1300 рядов. Каждое новое значение метки — новый ряд: метка с идентификатором запроса или с адресом клиента раздувает базу.
promtool ничего не напечатал и вышел с кодом 0 — под выражение не
попал ни один ряд:
curl -s localhost:9090/api/v1/label/job/values, какие ряды у
метрики — /api/v1/series с --data-urlencode 'match[]=up';> …;rate короче двух интервалов сбора, или Prometheus запущен
меньше минуты назад;node_network_*: у неё только lo, а
экспортёр его пропускает (node-exporter).У rate нет окна: rate(x) вместо rate(x[1m]).
Первое — значение метки без кавычек: up{job=node} вместо
up{job="node"}. Второе — метки группировки без скобок: sum by job
вместо sum by (job). 1:8 — строка и позиция ошибки в выражении.
После on (…) или ignoring (…) одному ряду с одной стороны
подходят несколько с другой. Если так и задумано — добавь
group_left (много рядов слева) или group_right (справа).
Сырое значение счётчика упало до нуля — процесс перезапустился.
rate и increase это учитывают. delta и вычитание
x - x offset 5m — нет: на сбросе они дают отрицательное число.
Prometheus держит выбранные точки в памяти, пока считает запрос.
{__name__=~".+"} за [1d] или rate по всем рядам за неделю на
машине с 512 МиБ могут занять всю память, и ядро завершит Prometheus
(oom-killer). Начинай с узкого селектора и короткого окна.
@[…] в дату.=~.Есть неточность? Сообщить об ошибке в статье