Prometheus - мониторинг и алертинг

Prometheus - инструмент для сбора данных и мониторинга за ними, который состоит из:

1. Time-series databases - хранит наши метрики (каждая запись имеет timestamp, когда она была туда добавлена).

* таблица с данными в TSDB грубо говоря выглядит так:

2. Retrieval - компонент который знает о наших приложениях (знает как получить метрики). Он с некоторой периодичностью собирает их и складывает в TSDB.

3. Prometheus targets - это наши приложения (микросервисы) или exporters (например php-fpm_exporter).

4. Grafana - инструмент мониторинга метрик:

В графане можно и настраивать алертинг, поэтому алертинг от прометея пока не рассматриваем.

5. VMUI (опционально) - чтобы через UI посмотреть отдельную метрику.

Сбор метрик в приложении

Подавляющее большинство php проектов работает с framework Symfony, а значит используем prometheus-metrics-bundle .

Бандл "из коробки" собирает несколько метрик, в основном это подсчет ответов по статусам, но главное:

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

Вот так выглядит страничка, которую приложение должно отдать на GET /metrics:

# HELP http_requests_total Requests made to public API
# TYPE http_requests_total counter
http_requests_total{method="POST", url="/login"} 2
http_requests_total{method="GET", url="/"} 5

Разберем строку метрики по кусочкам.

  • HELP — описание для помощи людям (комментарий).
  • TYPE — тип метрики (например для http_requests_total это  counter). Конечно Prometheus нет никакой разницы что написано в комментарии, это как HELP, чтобы было проще работать. Но библиотеки, которыми мы пишем метрики, построены вокруг этих типов (опираются на эти комментарии). Поэтому, некоторые функции в запросах корректно работают только для определенных типов. То есть можно считать TYPE соглашением о том, как себя ведет значение этой метрики.
  • http_requests_total — имя метрики (выбирайте сами, как Вам удобнее).
  • {...} — набор key-value лейблов (можно еще называть их тегами). Важно: каждое новое значение лейбла – это уже новый временной ряд (новая таблица). Поэтому не надо злоупотреблять. Хороший лейбл ограничен в возможных значениях. Получается User-Agent туда писать плохо, а вот название и мажорную версию браузера – ОК. Юзернейм, если их сотни – сомнительно, а если их десятки – ОК (api-клиенты внутреннего сервиса, например).
  • число справа — значение метрики (64-bit float aka double);

Магия: после сбора данных, в БД добавляется еще поле timestamp.

Нюансы типов (TYPE): 

counter — монотонно возрастающее число. Никогда не убывает! Может быть сброшен в ноль, например, при рестартах сервиса, который пишет метрику. Но, у Prometheus есть специальные функции, которые это учитывают: increase(), add(x)

Как узнать, сколько запросов было за единицу времени, когда у нас всего одно число? Посмотреть на дельту, т.к. Prometheus сохраняет снимки этого числа каждые 30 секунд. Ну и понадобится дополнительный костыль, если приложение перезапустилось, и счетчик вдруг сбросился в ноль – это уже учтено в функциях, которые работают со счетчиками.

histogram — агрегация чего-то самим приложением, когда нам интересно знать распределение величин по заранее определенным группам (buckets). API: observe(x)

Например, мы хотим знать длительность HTTP-запросов. Определимся, какое время считать хорошим, какое плохим, и насколько детально мы хотим это знать. Можно сказать, качественное распределение:

  • <= 0.1 сек. — хороший запрос, ожидаем, что таких будет большинство;
  • <= 1 — сойдет, но лучше бы знать, что такие встречаются;
  • <= 5 — подозрительно, пойдем смотреть код, если таких окажется много;
  • больше 5 — вообще плохо, для однообразия можно сказать, что это <= infinity.

Подробнее про типы метрик отлично написано здесь.

Векторы

В Prometheus есть 2 вида представления данных, они называются векторы, вот они:

  • Instant Vector (/api/v1/query) - возвращает данные указанного timestamp (или последнего известного timestamp).
  • Range Vector (/api/v1/query_range): чтобы посмотреть развитие метрики со временем, вы можете указать диапазон времени в запросе к Prometheus. В итоге получите вектор, объединяющий все значения, записанные за выбранный период.

Instant vector

Instant vector - одно число относительно конкретного timestamp (набор временных рядов, где каждая временная метка соответствует одной точке данных в этот «момент»).

Допустим в timeserial database есть записи:

Метрика (временной ряд)Время (unix timestamp)Значение (double)
{__name__="seo_http_requests_total", action="all", app="seo", ...}170584927067243
{__name__="seo_http_requests_total", action="all", app="seo", ...}17058492722475960
{__name__="seo_http_requests_total", action="all", app="seo", ...}17058492723331878

Прометей на запрос instant vector достанет запись соответствующую запрошенной временной метке, например запрос:

https://site.ru/prometheus/api/v1/query?query=seo_http_requests_total{action=%22all%22}&time=1687267141'

Ответ:

{
    "status": "success",
    "isPartial": false,
    "data": {
        "resultType": "vector",
        "result": [
            {
                "metric": {
                    "__name__": "seo_http_requests_total",
                    "action": "all",
                    "app": "seo",
                    "container": "seo-php-fpm",
                    "instance": "10.0.104.124:8000",
                    "namespace": "production",
                    "node": "infra-k8s9-worker26",
                    "pod": "seo-deployment-7ffc6d8b6-w2lbn",
                    "pod_template_hash": "7ffc6d8b6"
                },
                "value": [
                    1705849272,
                    "2475960"
                ]
            },
            {
                "metric": {
                    "__name__": "seo_http_requests_total",
                    "action": "all",
                    "app": "seo",
                    "container": "seo-php-fpm",
                    "instance": "10.0.168.77:8000",
                    "namespace": "production",
                    "node": "infra-k8s9-worker06",
                    "pod": "seo-deployment-7ffc6d8b6-z5dcl",
                    "pod_template_hash": "7ffc6d8b6"
                },
                "value": [
                    1705849272,
                    "3331878"
                ]
            }
        ]
    }
}

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

Визуализация данных собранных с каждого ядра восьмиядерного компьютера выглядит так:

На картинке слеваНа картинке справа
значение каждого ядра процессора обозначено отдельным цветом значение каждого ядра процессора обозначено одним цветом, но зато все значения одного процессора в один момент времени собраны в отдельную колонку

Range Vector

Range vector -  для каждого момента времени x мы имеем точку со значением метрики в этот момент: f(x), и еще заглядываем в прошлое и берем несколько предыдущих точек: [f(x-30s), f(x-60s), f(x-90s), ...]. 30 секунд здесь берутся из-за того, что Prometheus собирает значения метрик с таким интервалом, между ними просто ничего нет.

Указание диапазона дат времени

Можно указывать обычным способом - от 2024-01-21T11:10:30 до 2024-01-21T11:11:30

curl 'https://site.ru/prometheus/api/v1/query_range?start=2024-01-21T11:10:30.000Z&end=2024-01-21T11:11:30.000Z&step=15s&query=seo_http_requests_total{action=%22all%22}'

Можно с помощью timestamps - start=1706016000 end=1706016061:

https://site.ru/prometheus/api/v1/query_range?query=seo_http_requests_total%7Baction%3D%22all%22%7D&start=1706016000&end=1706016061&step=1m
{
    "status": "success",
    "isPartial": false,
    "data": {
        "resultType": "matrix",
        "result": [
            {
                "metric": {
                    "__name__": "seo_http_requests_total",
                    "action": "all",
                    "antiaf": "seo",
                    "app": "seo",
                    "container": "seo-php-fpm",
                    "instance": "10.0.104.33:8000",
                    "namespace": "production",
                    "node": "infra-k8s9-worker26",
                    "pod": "seo-deployment-6564f5964d-zr7rs",
                    "pod_template_hash": "6564f5964d"
                },
                "values": [
                    [
                        1706016000,
                        "635560"
                    ],
                    [
                        1706016060,
                        "636833"
                    ]
                ]
            },
            {
                "metric": {
                    "__name__": "seo_http_requests_total",
                    "action": "all",
                    "antiaf": "seo",
                    "app": "seo",
                    "container": "seo-php-fpm",
                    "instance": "10.0.218.3:8000",
                    "namespace": "production",
                    "node": "infra-k8s9-worker04",
                    "pod": "seo-deployment-6564f5964d-bvkkl",
                    "pod_template_hash": "6564f5964d"
                },
                "values": [
                    [
                        1706016000,
                        "71949"
                    ],
                    [
                        1706016060,
                        "73252"
                    ]
                ]
            }
        ]
    }
}

Запрос пишется как обычно, только добавляем интервал в квадратных скобках в конце.

http_requests_total{job="prometheus"}[5m]

На что влияет число в квадратных скобках: благодаря ему можно тюнить степень «сглаживания» или «разрешение» (точность).

  • больше интервал — более гладкий результат, видно тренд (общую картину);
  • меньше интервал — более шумный результат, видно пики и резкие скачки;
  • слишком малый интервал и не захватили минимум две точки — нет результата.

Range vector нельзя вывести на график (см. пример ниже — слишком много данных, непонятно, что выводить). Его нужно сначала обработать какой-то функцией и получить instant vector, который уже нормально рисуется. Собственно, для этого он и нужен — чтобы можно было применять всякие навороченные функции, которым нужны не только точки для графика, но и «взгляд в прошлое» по каждой точке, чтобы брать производную, считать дельту и прочее. Конкретные функции и их юзкейсы будут ниже, а пока что посмотрим, как достать range vector из базы.

Параметры запроса 

query - обязательный параметр, тут указывает имя метрики, например seo_http_requests_total{action="all"}:

https://site.ru/prometheus/api/v1/query?query=seo_http_requests_total%7Baction%3D%22all%22%7D

time=1705849271 (timestamp):
- если не указывать, возвратятся данные за последний timestamp известный прометею (по умолчанию в пределах 5 минут)
- если указать, то возвратится вектор созданный в указанное время (если именно в это время нет данных, то рядом)

https://site.ru/prometheus/api/v1/query?query=seo_http_requests_total%7Baction%3D%22all%22%7D&time=1705849271

step=1 - можно не указывать, он по-умолчанию равен 1, пример:

https://site.ru/prometheus/api/v1/query?query=seo_http_requests_total%7Baction%3D%22all%22%7D&step=1

Метрики и лейблы можно матчить по равно/неравно и регулярками, подошло/не подошло. Операторы: = != =~ !~

http_requests_total{environment=~"staging|testing|(dev.*)", method!="GET"}

Выбор интервала

Зависит от сценариев использования.

Для запросов, которые пишутся руками во время экспериментов: хотите сглаженный график, чтобы было видно, что с ним происходит в целом — берите интервал побольше. Если нужно видеть, как значение «скачет» — берите поменьше, но не менее 1 минуты (2*scrape_interval, который у нас 30 секунд).

Для запросов, которые вы пишете в Grafana, важно учитывать текущий масштаб графика, поэтому используйте переменную $__rate_interval (и ни в коем случае не $__interval).

Если вдруг у вас вместо Prometheus используется Clickhouse, из-за бага в парсере запросов кликхауса, вы не сможете использовать графановские умные интервалы, используйте свой кастомный.

Чтобы подробнее объяснить эти моменты, понадобится отдельная статья, уже с прицелом на Grafana и с примерами из нее, поэтому здесь оставим без деталей.

 

PromQL

Запросить метрики у прометея можно с помощь PromQL. Так делает, например, графана и потом показывает нам графики.

Возьмем популярный пример - RPS - и разберем его: sum(rate(seo_http_requests_total{action="all"}[1m]))

seo_http_requests_total{action="all"} - метрика, а внутри нее action="all" значит что мы видим RPS по всем роутам

Источники: 1 - 2 - 3 - 4 - 5 - 6 - 7


11.07.2016 12:42

Комментарии

Комментариев пока нет.


Copyrights © 2007 - 2026 YaPro.Ru