PROM 07: Использование PromQL для анализа метрик

Описание:

Всем привет!

За первые шесть заданий мы прошли большую тему под названием - "Базовая настройка и сбор метрик", а так же посмотрели на функции автодискавери в Prometheus. На данный момент вы уже сможете настроить prometheus в своей инфраструктуре и подключить всю инфраструктуру, доступную вам, к мониторингу. Следующий важный этап при работе с системой мониторинга - это умение анализировать полученные метрики. Согласитесь, что бессмысленно собирать все эти данные, если вы их даже не посмотрите. Итак, в этом задании мы с вами разберемся с типами данных которыми оперирует promethues, научимся их фильтровать, разберемся с операторами, а так же поговорим про встроенные функции, которые вы сможете использовать для обработки полученных метрик.

В реальной жизни вам потребуется достаточно часто работать с promql. Он пригодится вам как минимум для настройки правил алертинга. А так конечно же вы будете прибегать к нему для анализа текущего состояния инфраструктуры и разобра прошедших инцидентов. Итак, поехали!

Основные типы данных в prometheus

Давайте посмотрим на примеры метрик самого prometheus - он выдает метрики в своем же формате, так что вы сможете мониторить prometheus им же самим:

root@prom-test:/opt/prometheus# curl localhost:9090/metrics
... skipped ...

# HELP prometheus_http_requests_total Counter of HTTP requests.
# TYPE prometheus_http_requests_total counter
prometheus_http_requests_total{code="200",handler="/metrics"} 55

... skipped ...

# HELP prometheus_tsdb_blocks_loaded Number of currently loaded data blocks
# TYPE prometheus_tsdb_blocks_loaded gauge
prometheus_tsdb_blocks_loaded 1

... skipped ...

Первая строка HELP является вспомогательной и просто добавляет комментарий к нашей метрике - чтобы было понятно к чему она относится. А вот вторая строка - TYPE задает тип нашей метрики. Типы метрик можно представить себе как типы переменных в программировании. К примеру, при разработке на golang вы можете встретить такие типы переменных как int - целое число, string - строка, float - дробное число и так далее. Типы нужны для того, чтобы компилятор понимал сколько памяти необходимо выделить переменной и как с ней работать. Типы метрик в prometheus решают ту же задачу - благодаря им вы можете использовать встроенные функции для расчета каких-либо значений по полученным метрикам. И функции эти работают на базе типов - какие-то функции могут работать только с одним типом метрик, другие с другим.

В Prometheus существует всего 4 типа метрик, давайте рассмотрим каждый из них:

Counter - это простой счетчик. Его особенность заключается в том, что значение этой метрики не может уменьшаться. Например, метрика processed_requests - количество обработанных запросов. Согласитесь, что она не может уменьшаться - при каждом новом запросе она будет увеличиваться на единицу.

Gauge - этот тип отвечает за простую метрику, которая может как увеличиваться, так и уменьшаться. Хороший пример такой метрики - температура. На данный момент она составляет 18 градусов, через пару часов будет 21 градус, а ночью опустится до 10.

Из примера выше вы можете увидеть две метрики - prometheus_http_requests_total с типом counter - она отображает общее количество запросов. Из вывода видно, что всего запросов на prometheus пришло 55 штук. Эта метрика может только увеличиваться. Вторая метрика - prometheus_tsdb_blocks_loaded с типом gauge показывает количество блоков time series database, которые были загружены. Данная метрика может как расти так и уменьшаться в зависимости от типов запросов, которые пришли к prometheus - запросили много данных, prometheus загрузил в память много блоков базы. Запросы закончились - prometheus выгрузил неиспользуемые данные на диск.

Итак, с counter и gauge я думаю все понятно - это самые простые типы данных. Давайте теперь перейдем к более сложным типам:

Histograms - гистограммы. Собирает несколько данных о метрике - общее количество значений, их сумма, а так же разбивка по группам. Используется чаще всего для сбора временных метрик (например, время ответа). Все значения рассчитываются на стороне сервера.

Summaries - по сути те же гистограммы, но все расчеты производятся на клиенте, поэтому клиент может отъедать некоторый процент процессорного времени. Зато не нагружают сервер prometheus, в отличие от Histograms.

Важно: Тут очень важно отметить что такое квантили и процентили (персентили). Давайте разберем это понятие на примере. Представьте, что наш nginx собирает в логах информацию о времени обработки запроса. То есть в лог попадает строка - такой-то айпи адрес, запросил такую-то страницу и мы отдали ее ему за 2 секунды. Таких строк может быть очень много, но в итоге вы, как администратор системы, хотите видеть какую-то цифру, которая отображает текущее состояние системы - чтобы на основании ее сделать вывод все ли хорошо или плохо.
Первым на ум приходит использовать простое среднее - взяли 10 000 строк, сложили все время ответов и поделили на 10 000 (их количество). Допустим мы получили значение 11,8 секунд. То есть среднее время ответа - 11,8 секунд. И вроде же все хорошо, но на самом деле простое среднее без дополнительных показателей не может объективно отражать окружающую действительность.
Почему? Представьте что 9970 запросов выполнились за 1 секунду, а оставшиеся 30 были выполнены за 1 час (например генерировались какие-то отчеты). Тогда если мы подсчитаем среднее - то получим как раз 11,8 секунд среднее время выполнение запроса. Но это же неправда! БОльшая часть из них (9970 или 99,7%) выполнилась за 1 секунду - то есть все было хорошо и пострадали только 30 запросов. Таким образом вы можете видеть, что проблема простого среднего заключается в том, что при его использовании единичные пики (выбросы) очень сильно влияют на финальный результат.
Чтобы такого не происходило - нам нужна какая-то другая метрика - например персентиль. Рядом с персентилем всегда указывается процент - например 95% персентиль (или p95). Если мы подсчитаем 95 процентный персентиль от нашего набора данных (9970 запросов по 1 секунде и 30 запросов по 3600 секунд), то он будет равняться 1 секунде, что можно перевести как - 95 процентов запросов обрабатываются за 1 секунду или меньше. Если же мы возьмем p99 (99% персентиль) - то он так же будет равняться 1 секунде - поскольку 99% запросов обрабатываются за 1 секунду или меньше.
Давайте посмотрим как рассчитывается персентиль - тогда точно отпадут все вопросы. Для начала вам нужно взять и отсортировать все ваши данные по возрастанию. Давайте возьмем 10 запросов с разным временем ответа - первые пять запросов будут отдаваться за 1 секунду, а каждый следующий на 2 секунды дольше: 1 1 1 1 1 3 5 7 9 11
Теперь нам нужно взять процент персентиля, который мы хотим увидеть и отсчитать нужное количество данных слева направо - именно это значение и будет значение персентиля. К примеру если нам нужно узнать для данного набора 30% персентиль - то мы умножаем 10 (кол-во значений) на 0,3 и получаем 3 - то есть нам нужно третье значение слева. Оно равно единице. Соотвественно и персентиль 30% равен единице. И он означает, что 30% всех значений (то есть наших запросов) были обработаны за 1 секунду или меньше. Ну тут все логично - действительно все что стоит левее меньше или равно единице. Давайте возьмем 50% персентиль (он еще называется медианой) - 10 * 0,5 = 5 - то есть нам надо взять пятое значение слева. Оно так же равно единице (1). То есть 50% запросов были обработаны за 1 секунду или меньше. Ну и напоследок возьмем 90% персентиль - 10 * 0,9 = 9 - берем 9ое число слева - оно равно 9. Таким образом 90% всех запросов были обработаны за 9 секунд или быстрее.
Подводя итог - благодаря персентилям вы можете видеть разбивку ваших данных по группам - например время ответа веб сервер - сколько именно пользователей за какое время получили ответ. Может быть такая ситуация, что 99% запросов обрабатывается быстро - до 100ms, а оставшийся процент обрабатывается уже за 10 секунд. Тут надо искать причину, но будет абсолютно очевидно, что больших проблем у вас нет - система работает штатно для 99% пользователей.
Кстати, очень советую книгу по статистике, которую прочитал сам и перечитывал много раз - https://www.mann-ivanov-ferber.ru/books/golaya-statistika/ - после ее прочтения вы всегда будете обращать внимание на слово среднее. Если вам кто-то говорит про среднее без любых других данных - то скорее всего он вам врет. (Типа люди едят капусту, а чиновники мясо. В среднем все едят голубцы).

Но мы отвлеклись - итак, histograms & summaries позволяют считать персентили для ваших метрик. Главное отличие между ними состоит в том, что расчет персентили для histograms производится на сервере с prometheus, а summaries считается на каждом клиенте по отдельности.

Давайте посмотрим на примеры метрик histograms и summaries - возьмем мы их так же с самого prometheus:

# curl localhost:9090/metrics

... skipped ...

# HELP prometheus_http_request_duration_seconds Histogram of latencies for HTTP requests.
# TYPE prometheus_http_request_duration_seconds histogram
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="0.1"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="0.2"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="0.4"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="1"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="3"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="8"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="20"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="60"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="120"} 9
prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="+Inf"} 9
prometheus_http_request_duration_seconds_sum{handler="/metrics"} 0.027508920000000003
prometheus_http_request_duration_seconds_count{handler="/metrics"} 9

... skipped ...

# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds_sum 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds_count 1

... skipped ...

Итак - первая метрика - prometheus_http_request_duration_seconds_bucket - это histogram, которая рассчитывает как быстро обрабатывает http запросы к API сам prometheus. Как видно из вывода - гистограмма рассчитывает два параметра - _sum (prometheus_http_request_duration_seconds_sum) - это сумма всех измерений, _count (prometheus_http_request_duration_seconds_count) - количество измерений и дальше идут _bucket с различными группами - {le} - она показывает сколько измерений попало в ту или иную группу. Например prometheus_http_request_duration_seconds_bucket{handler="/metrics",le="20"} 9 - в группу le=20 (то есть время ответа 20 секунд или менее) попало 9 запросов. Таким образом клиентская библиотека на своей стороне всего лишь распределяет запросы по группам и увеличивает значение счетчика, тем самым практически не затрачивая никаких ресурсов.

Вторая метрика - summary - prometheus_tsdb_wal_fsync_duration_seconds - она так же рассчитывает _sum (prometheus_tsdb_wal_fsync_duration_seconds_sum) - сумму измерений, _count - (prometheus_tsdb_wal_fsync_duration_seconds_count) - количество измерений. А вот дальше идут отличия - summary сразу рассчитывает нужные квантили (персентили) - 50%, 90% и 99%:

prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.002031888
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.002031888

То есть мы сразу можем сказать, что 90% запросов занимают 0.002031888 секунды или меньше. Несколько минусов summaries заключаются в том, что вы не можете рассчитать новый персентиль, если он не был задан изначально - то есть сейчас сказать какое имеет значение 70% персентиль нельзя. Ну и рассчитывается он в риал тайме, тем самым нагружает клиентское приложение, в отличие от гистограм, которые считаются на сервере.

Итак, с основными типами данных разобрались - давайте попробуем теперь поработать с этими данными. В примерах так же будем использовать метрики самого prometheus.

Фильтрация данных

Про фильтрацию мы уже говорили в предыдущих заданиях, но давайте все же повторимся и посмотрим на общий вид нашей метрики:

metric_name{tag1="data1", tag2="data2"} X

В данном случае у нас есть имя метрики - metric_name, в фигурных скобках указываются теги - tag1="data1", tag2="data2" - они могут быть абсолютно любыми и после пробела указывается значение данной метрики - X. X может быть только числом - float.

Чтобы вывести последнее значение любой метрики - в promql вы просто можете указать ее имя:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ up
up{instance="localhost:8080", job="app"} => 1 @[1622717586.873]
up{instance="localhost:9090", job="prometheus"} => 1 @[1622717586.873]

В данном случае мы вывели последние значения метрики up. Чтобы отфильтровать значения - мы можем добавить к запросы теги, которые мы хотим там видеть:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up{job='app'}"
up{instance="localhost:8080", job="app"} => 1 @[1622717644.331]
root@prom-test:/opt/prometheus#

Таким образом prometheus вывел нам все метрики up у которых тег job идентичен app. Помимо прямого сравнения вы так же можете использовать отрицание и даже regexp:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up{job!='prometheus'}"
up{instance="localhost:8080", job="app"} => 1 @[1622717699.7]
root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up{job=~'..p'}"
up{instance="localhost:8080", job="app"} => 1 @[1622717711.238]
root@prom-test:/opt/prometheus#

Кстати, в prometheus вы можете использовать секретный тег __name__, который содержит имя метрики. Таким образом вы можете одним запросом вывести все метрики с интересующим вас именем:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "{__name__=~'^up$'}"
up{instance="localhost:8080", job="app"} => 0 @[1622759105.491]
up{instance="localhost:9090", job="prometheus"} => 1 @[1622759105.491]

Помимо фильтрации по тегам вы так же можете фильтровать метрики по текущим значениям - например давайте выведем все метрики up, у которых значение равно 1:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up == 1"
up{instance="localhost:8080", job="app"} => 1 @[1622717784.272]
up{instance="localhost:9090", job="prometheus"} => 1 @[1622717784.272]

А теперь все метрики app, у которых значение метрики не равно 1:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up != 1"

root@prom-test:/opt/prometheus#

Все логично - вывод пустой - у нас нет таких метрик. Или выведем все метрики up, у которых значение больше 0:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up > 0"
up{instance="localhost:8080", job="app"} => 1 @[1622717832.933]
up{instance="localhost:9090", job="prometheus"} => 1 @[1622717832.933]

Важно: Благодаря использованию фильтрации по значению и по тегам вам становится очень просто следить за состоянием системы и искать возникающие проблемы. К примеру, вы можете вывести все хосты, которые относятся к dev окружению (env="dev") и используют cpu больше чем на 70% (> 0.7). В этом и заключается реальная сила prometheus - promql. Представьте, что у вас есть сотни устройств и хостов и вам нужно быстро отфильтровать вашу инфраструктуру по каким-то критериям - окружение, количество запросов, время ответа и так далее - вы сможете сделать это буквально за одну секунду!

Итак, с базовой фильтрацией разобрались - переходим к работе с операторами!

Работа с базовыми функциями

Перед тем, как начать работать с операторами важно рассказать про типы данных, которыми оперирует promql. Это не типы метрик, а именно типы данных, которые получаются в результате работы функций и операторов. Итак, существует три типа данных:

Instant Vector - это несколько time series метрик, которые отражают одно значение за определенное время, например:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up"
up{instance="localhost:8080", job="app"} => 1 @[1622719041.253]
up{instance="localhost:9090", job="prometheus"} => 1 @[1622719041.253]

Здесь отображается значение метрики up для всех тегов за один и тот же timestamp - 1622719041.253.

Range Vector - это несколько time series метрик, которые отражают несколько значений за определенный интервал времени, например:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up[2m]"
up{instance="localhost:8080", job="app"} =>
1 @[1622718987.573]
1 @[1622719002.573]
1 @[1622719017.573]
1 @[1622719032.573]
1 @[1622719047.573]
1 @[1622719062.573]
1 @[1622719077.573]
1 @[1622719092.573]
up{instance="localhost:9090", job="prometheus"} =>
1 @[1622718989.926]
1 @[1622719004.926]
1 @[1622719019.926]
1 @[1622719034.926]
1 @[1622719049.926]
1 @[1622719064.926]
1 @[1622719079.926]
1 @[1622719094.926]

Здесь отображается значение метрики up за последние две минуты. При использовании range vector вы указываете временной промежуток в квадратных скобках. Перед ними вы так же можете использовать фильтрацию по тегам:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up{job='app'}[2m]"
up{instance="localhost:8080", job="app"} =>
1 @[1622719047.573]
1 @[1622719062.573]
1 @[1622719077.573]
1 @[1622719092.573]
1 @[1622719107.573]
1 @[1622719122.573]
1 @[1622719137.573]
1 @[1622719152.573]

Scalar - простые числа с плавающей запятой. Вы сможете использовать их, например, прибавляя к метрикам или умножая на них.

Теперь переходим к операторам. В целом они все интуитивно понятны:

+ сложение

- вычитание

* умножение

/ деление

% модуль

^ возведение в степень

Данные операторы работают как между скалярными величинами (5*5), так и между instant vector, например:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "2 + 2"
scalar: 4 @[1622719951.177]
root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up + 1"
{instance="localhost:8080", job="app"} => 2 @[1622719953.617]
{instance="localhost:9090", job="prometheus"} => 2 @[1622719953.617]
root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "up + up"
{instance="localhost:8080", job="app"} => 2 @[1622719955.02]
{instance="localhost:9090", job="prometheus"} => 2 @[1622719955.02]
root@prom-test:/opt/prometheus#

В первом примере мы складываем просто два скалярных значения. Во втором прибавляем к метрике up скалярное значение 1. И в третьем примере складываем два instant vector'а.

Помимо стандартных сложений существуют так же операторы агрегирования - они позволяют агрегировать значения одного instant vector по разным тегам - например просуммировать количество запросов между всеми хостами с тегом env=dev. Приведем основные из них:

sum - суммирование

min - взять минимальное значение

max - взять максимальное значение

avg - взять среднее значение

count - подсчитать количество элементов в векторе

Давайте попробуем просуммировать все значения всех метрик up:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "sum(up)"
{} => 2 @[1622720202.092]

В данном случае prometheus взял все метрики up, откинул все теги и просуммировал их значения - в итоге получилось 2. Можно сделать разбивку по job:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "sum by (job) (up)"
{job="app"} => 1 @[1622720257.153]
{job="prometheus"} => 1 @[1622720257.153]

В данном случае prometheus взял метрику up, сгруппировал их по тегу job и просуммировал значения в каждой из групп. Поскольку в каждой группе (app и prometheus) у нас всего лишь по одной метрике - то и значения получились идентичные исходным.

С помощью данных операторов вы можете суммировать количество запросов по всем вашим серверам или вытаскаивать хосты с самым высоким потреблением памяти - по сути выводить топ 5 самых нагруженных серверов.

Работа с функциями в prometheus

Итак, переходим теперь к самому интересному - функциям. С помощью функций вы можете обрабатывать ваши метрики и рассчитывать интересующие вас значения. Как уже говорилось ранее - функции работают с различными типами метрик - это обычно четко указывается в документации. Функций в prometheus действительно много и подробнее про них вы сможете прочитать в документации. Здесь мы разберем самые частые из них. И начнем с функции rate.

Функция rate принимает на вход range vector и дальше выполняет простое преобразование - берет разность последнего и первого значения и делит их на количество секунд в интервале - таким образом вы получаете скорость роста счетчика. Данная функция работает только с типом данных counter. Давайте посмотрим на пример:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "prometheus_http_requests_total{}"
prometheus_http_requests_total{code="200", handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 27 @[1622721465.532]
prometheus_http_requests_total{code="200", handler="/metrics", instance="localhost:9090", job="prometheus"} => 366 @[1622721465.532]
prometheus_http_requests_total{code="400", handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 9 @[1622721465.532]

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "rate(prometheus_http_requests_total{}[2m])"
{code="200", handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 0 @[1622721473.43]
{code="200", handler="/metrics", instance="localhost:9090", job="prometheus"} => 0.06666666666666667 @[1622721473.43]
{code="400", handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 0 @[1622721473.43]
root@prom-test:/opt/prometheus#

В первый раз мы просто запросили значения наших метрик, а во второй раз - попросили prometheus рассчитать нам среднее количество запросов за последние две минуты. prometheus взял текущее значение метрики prometheus_http_requests_total после чего вычел значение метрики prometheus_http_requests_total, которое было 2 минуты назад и после этого поделил полученное значение на 120 секунд (2 минуты). Таким образом мы получили среднее количество запросов в секунду.

Так же мы можем использовать оператор sum для суммирования количества запросов по всем одинаковым инстансам:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "sum by (instance) (rate(prometheus_http_requests_total{}[2m]))"
{instance="localhost:9090"} => 0.06666666666666667 @[1622721815.76]

Тут происходит все то же самое - мы получили с помощью rate количество запросов в секунду, а после этого сложили наши метрики по тегу instance - все у кого он совпадал были сложены. Таким образом вы можете простым запросом вывести, например, количество запросов в секунду на всех dev и prod серверах.

Помимо функции rate существует функция irate - она делает все то же самое, но берет разность не первого и последнего значения, а разность последнего и предпоследнего значения. То есть, ей без разницы какой интервал вы укажите - [2m] или [10m] - для рассчета она возьмет последнее и предпоследнее полученное значение.

Следующая функция в нашем списке - delta. Она работает только с типом метрик gauge и рассчитывает разность первого и последнего значения в range vector. Например:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "delta(prometheus_tsdb_blocks_loaded[2m])"
{instance="localhost:9090", job="prometheus"} => 0 @[1622722060.54]

Таким образом delta возьмет последнее значение метрики prometheus_tsdb_blocks_loaded и вычтет из него значение метрики prometheus_tsdb_blocks_loaded 2х минутной давности.

Еще одной интересной функцией для gauge метрик является predict_linear - она предсказывает значение метрики на заданное количество секунд вперед. При этом используется линейная регрессия. То есть по сути строится прямая по средним значениям в прошлом и на ее основе предсказываются будущие значения:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "predict_linear(prometheus_tsdb_blocks_loaded[120m], 120)"
{instance="localhost:9090", job="prometheus"} => 1.0048419915591933 @[1622722310.225]

В данном случае мы взяли значение метрики prometheus_tsdb_blocks_loaded за последние 2 минуты и попробовали предсказать значение на 120 секунд в будущем. Эту функцию очень удобно использовать с количеством свободного места на диске - она сможет предсказать когда закончится место на диске.

Ну и в заключении давайте посмотрим на функцию, которая предназначена для работы с гистограмами. Поскольку summaries считаются сразу на клиенте, то данная функция не применяется к summaries. Давайте попробуем рассчитать 85% персентиль на время ответа prometheus по http:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "histogram_quantile(0.85, prometheus_http_request_duration_seconds_bucket)"
{handler="/metrics", instance="localhost:9090", job="prometheus"} => 0.085 @[1622722586.628]
{handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 0.085 @[1622722586.628]

В данном случае мы используем функцию histogram_quantile с параметром 0.85 (это 85%) и указанием histogram метрики, которую нужно использовать - prometheus_http_request_duration_seconds_bucket. Так же вы можете рассчитать значение на временном отрезке, добавив функцию rate:

root@prom-test:/opt/prometheus# ./promtool query instant http://localhost:9090/ "histogram_quantile(0.85, rate(prometheus_http_request_duration_seconds_bucket[10m]))"
{handler="/api/v1/query", instance="localhost:9090", job="prometheus"} => 0.085 @[1622722648.458]
{handler="/metrics", instance="localhost:9090", job="prometheus"} => 0.085 @[1622722648.458]

Тут рассчитывается та же метрика, но за 10 минутный интервал.

Итоги

Итак, давайте резюмируем все то, что мы сегодня обсуждали. Во-первых, мы разобрались с типами метрик, которые есть в prometheus. Так же мы научились фильтровать их и выводить значения на определнном временном промежутке. Так же мы разобрались с тем как вы можете модифицировать значения с помощью стандартных операторов, а так же агрегировать значения метрик с помощью операторов агрегирования. Ну и в заключение поговорили о том, как вы можете использовать функции для расчета новых значений ваших метрик.

В следующий раз мы поговорим о том, как вы можете визуализировать полученные данные в веб интерфейсе.

Полезные ссылки:

Histograms and summaries

4 type of prometheus metrics

Prometheus Functions

Query Examples

Promql for humans

Задание:

В этом задании вам будет необходимо установить и подключить node_exporter к вашему prometheus серверу, а так же написать два запроса на promql: который выводит использование пользовательского user cpu в процентах и процент свободного места на диске. На подготовленной виртуальной машине уже установлен Prometheus.

Критерии оценки выполнения задания:

Установите экспортер node_exporter:

1.1. Исполняемый файл экспортера node_exporter должен находиться внутри отдельной директории /opt/node_exporter.

1.2. Экспортер node_exporter должен быть запущен как сервис c помощью systemd и быть описан в файле /etc/systemd/system/node_exporter.service.

1.3. Prometheus должен собирать информацию с node_exporter.

Напишите 2 запроса:

2.1. Первый запрос должен выводить суммарный процент использования cpu для режима user (mode=user) со всех существующих node_exporters (просуммированный по instance). Запрос сохраните в файл /tmp/query1.txt. // Внутри запроса используйте irate.

2.2. Второй запрос должен выводить процент свободного места в корневом разделе (/). Запрос сохраните в файл /tmp/query2.txt. У Node exporter есть две метрики, которые отображают наличие свободного места. Вот отличия между ними:

"node_filesystem_avail_bytes" shows the available space you have as a user and the "node_filesystem_free_bytes" is the "physical" free space which includes the reserved space for root.

В решение используйте node_filesystem_avail_bytes.