Модуль 2 · Как работает Prometheus · Макаров М. Н.

Модуль 2 · как работает prometheus · сбор метрик

Глава 2.1

2.1

Что такое
Prometheus

В этой главе разобрано, для чего нужен Prometheus и с какими данными он работает. Сначала описана его задача, затем метрика и её отличие от записи в логе, затем временной ряд и части системы. В конце одно число проходит весь путь: от счётчика в коде приложения до ответа на запрос.

Категория
Устройство системы
Уровень
Вводный
Опирается на
Модуль 1: мониторинг, метрики и логи
Результат
Схема пути данных для остальных глав модуля

§1Задача Prometheus

Пока программа работает на компьютере разработчика, её состояние видно сразу: ошибки появляются в терминале, медленный ответ заметен глазами. После запуска на сервере этого контакта нет. Сервис принимает запросы, копит очередь задач и занимает память, а разработчик узнаёт о проблеме, только когда пользователи начинают жаловаться.

Чтобы узнавать о состоянии сервиса раньше, его нужно измерять. При этом одного измерения мало. Число «в очереди 40 задач» ничего не говорит, пока неизвестно, сколько их было час назад: 38 или 2. Поэтому измерения повторяют через равные промежутки и сохраняют вместе с временем.

Сравнение из жизни
В больнице

Медсестра по расписанию обходит палаты, измеряет температуру каждого пациента и записывает её в температурный лист вместе с временем. Врач по листу определяет, в какой час температура начала расти.

В Prometheus

Prometheus по расписанию обходит программы, забирает у каждой числа и записывает их вместе с временем. Разработчик по этим записям определяет, в какую минуту выросло число ошибок.

Точное определение повторяет это сравнение.

Prometheusсистема мониторинга · открытый исходный код

Программа-сервер, которая регулярно забирает у других программ числовые показатели, хранит их с отметками времени и отвечает на запросы по этим данным.

Prometheus создан в компании SoundCloud в 2012 году. Сервер написан на языке Go и состоит из одного исполняемого файла.

В определении названы три действия, и сервер выполняет их по порядку. Сначала идёт сбор: раз в несколько секунд сервер запрашивает у приложения его текущие показатели. Затем хранение: каждое полученное число записывается на диск вместе с моментом, когда оно получено. После этого становятся возможны запросы: человек спрашивает, сколько запросов обработано за последний час, и сервер считает ответ по сохранённым числам.

Три действия сервера Prometheusпорядок работы
1 · сборЗабрать числау приложения, раз в 15 секунд
2 · хранениеЗаписать с временемна свой диск
3 · запросыОтветить на вопроспо сохранённым числам

Запросы пишут на собственном языке Prometheus, он называется PromQL. По результатам запросов сервер ещё отправляет оповещения, но в этом модуле они не разбираются: сначала нужно понять, как данные попадают в базу.

Первое из трёх действий — сбор. Поэтому следующий вопрос: какие данные Prometheus забирает у программы.

§2Какие данные собираются

Prometheus забирает у программы только числа. Они похожи на показания приборной панели автомобиля. Одометр показывает, сколько километров машина проехала за всё время. Указатель топлива показывает, сколько бензина в баке сейчас. Оба прибора показывают по одному числу, и маршрут поездки по ним восстановить нельзя.

У программы такие же приборы. Она считает, сколько запросов обработала и сколько задач ждёт в очереди. Кто отправил запрос и что в нём было, по этим числам определить нельзя. Такое число называется метрикой: это числовой показатель, который программа считает о себе сама и показывает по запросу.

Считается метрика так. Программа хранит число в своей памяти и при каждом событии увеличивает его или записывает новое значение. Отдельные события она никуда не отправляет. Prometheus раз в несколько секунд забирает то значение, которое есть в памяти на этот момент.

Два вида чисел

Одометр и указатель топлива ведут себя по-разному, и у метрик есть те же два вида. Число первого вида только растёт, как одометр: оно считает события с момента запуска программы. Такая метрика называется counter, по-русски счётчик. Число второго вида растёт и уменьшается, как указатель топлива: оно показывает текущую величину. Такая метрика называется gauge, измеритель.

В таблице четыре примера. В левом столбце вопрос о сервисе, в среднем — метрика, которая на него отвечает.

Вопрос о сервисеМетрикаВид
Сколько запросов обработаноhttp_requests_totalcounter: только растёт, после перезапуска программы начинается с нуля
Сколько запросов уложилось в 0,1 сhttp_request_duration_seconds_bucket{le="0.1"}counter: набор таких счётчиков описывает скорость ответа
Сколько задач ждёт в очередиqueue_lengthgauge: растёт, когда задача приходит, и уменьшается, когда задача выполнена
Сколько памяти занимает процессprocess_resident_memory_bytesgauge: значение в байтах на момент запроса

Во всех четырёх строках значение метрики — одно число. Текста запроса, адреса клиента и текста ошибки в нём нет.

Подробности события в метрику не попадают. Их записывают в лог, и следующий раздел сравнивает эти два вида данных на одном примере.

§3Метрика и запись в логе

Разницу между метрикой и логом хорошо показывает магазин. Кассовый чек описывает одну покупку: что купили, во сколько, на какую сумму. Отчёт за день содержит несколько чисел: количество покупок и общую выручку. Чеков столько, сколько покупок, а число строк в отчёте от числа покупок не зависит.

Запись в логе — это чек: она описывает одно событие. Метрика — это строка отчёта: она содержит число по целой группе событий. На схеме ниже три запроса к приложению стенда записаны обоими способами. Слева строки лога, которые печатает сервер uvicorn. Справа метрика, которую получает Prometheus.

Три запроса: в логе и в метрикестенд модуля
Лог: одна запись на событие
"GET /items/1 HTTP/1.1" 200 OK
"GET /items/2 HTTP/1.1" 200 OK
"GET /items/500 HTTP/1.1" 404 Not Found
Метрика: одно число на группу
http_requests_total method="GET" status="200" 2
http_requests_total method="GET" status="404" 1

В логе три строки, по одной на запрос, и в каждой виден адрес. В метрике две строки: два успешных запроса сложены в число 2, запрос с ошибкой дал число 1. После тысячи запросов в логе будет тысяча строк, а в метрике останутся те же две строки с другими числами. Поэтому объём лога зависит от числа событий, а объём метрик — от числа групп.

Из этого следует, какие вопросы можно задать каждому виду данных. Метрика отвечает на вопрос «сколько»: сколько было ошибок и как это число менялось. Лог отвечает на вопрос «что произошло»: какой запрос вернул 404 и с какими параметрами. Найти конкретный запрос по метрике нельзя, потому что отдельных событий в ней нет.

Преобразование работает только в одну сторону. Из логов метрику получить можно: достаточно сосчитать записи со статусом 404. Из метрики лог получить нельзя: по числу 1 не определить, какой запрос вернул ошибку. Поэтому метрики и логи собирают разными системами. Документация Prometheus говорит об этом так: Prometheus собирает и обрабатывает метрики, а для логов она советует Grafana Loki или OpenSearch.

Одна строка метрики показывает число на текущий момент. Чтобы получить историю, Prometheus складывает такие числа в ряд.

§4Временной ряд

В §1 говорилось, что одно измерение мало что сообщает и нужна история. История одной величины в Prometheus называется временным рядом. Её устройство знакомо каждому, кого в детстве измеряли у дверного косяка.

Сравнение из жизни
Рост ребёнка на дверном косяке

Родители раз в полгода ставят отметку и пишут рядом дату. Одна отметка показывает рост сегодня. Все отметки вместе показывают, как ребёнок рос.

Показания в Prometheus

Prometheus сохраняет каждое полученное число вместе с временем. Одно число показывает состояние сейчас. Все числа вместе показывают, как состояние менялось.

Временной рядtime series · единица хранения Prometheus

Все сохранённые значения одной величины, расположенные по времени. Каждая запись ряда состоит из двух частей: отметки времени и значения.

Одна такая запись называется sample — отсчёт.

Так выглядит настоящий ряд. На стенде модуля Prometheus опрашивает приложение раз в 15 секунд и после каждого опроса записывает, удался ли он: 1 — удался, 0 — нет. Этот ряд называется up. Ниже восемь его отсчётов за две минуты.

Ряд up{job="api"} за две минутыPrometheus 3.5.0 · время UTC
время12:56:4512:57:0012:57:1512:57:3012:57:4512:58:0012:58:1512:58:30 значение11111111

Каждый столбец на схеме — один отсчёт: вверху время, внизу значение. Между соседними отсчётами 15 секунд, на стенде отклонение было не больше 4 миллисекунд. Отметку времени ставит Prometheus в момент начала опроса. Приложение время не передаёт: в §3 было видно, что в строке метрики есть только имя, метки и число.

Чем один ряд отличается от другого

У приложения стенда одна метрика http_requests_total, но в §3 у неё было две строки. Строки различались тем, что стоит в фигурных скобках. Эти пары «название — значение» называются метками. Метка уточняет, о чём число: status="404" означает, что посчитаны запросы с ответом 404.

Отсюда правило хранения: ряд определяется именем метрики и всеми метками сразу. Если отличается хотя бы одна метка, это другой ряд со своей историей. На стенде у метрики встретились три сочетания меток, поэтому рядов три.

Три ряда одной метрикистенд модуля
http_requests_total method="GET" status="200" 125
http_requests_total method="GET" status="404" 3
http_requests_total method="POST" status="405" 1

Из правила прямо следует ограничение. Каждое новое значение метки создаёт новый ряд, а каждый ряд занимает память сервера. Пока в метках стоят метод и код ответа, рядов три. Если добавить метку с идентификатором пользователя, рядов станет столько, сколько пользователей: при тысяче пользователей до трёх тысяч. Число рядов называют кардинальностью. Чтобы она не росла, в метки записывают значения из небольшого набора, известного заранее: метод запроса, код ответа, название очереди.

Подробнее: в каком виде хранится отсчёт

Отметка времени — целое число миллисекунд, прошедших с 1 января 1970 года по UTC. Значение — число с плавающей точкой двойной точности (float64).

Соседние отсчёты одного ряда мало отличаются, и хранилище записывает только разницу между ними. По документации, на один отсчёт уходит в среднем 1–2 байта. Над числами работают сложение и другие вычисления: сумма по всем копиям сервиса, скорость роста, доля ошибок. Текст допускается только в метках.

Известно, что хранится: ряды из отсчётов. Следующий раздел называет программы, которые эти ряды создают и сохраняют.

§5Части системы

Словом «Prometheus» называют и сервер, и набор программ вокруг него. В работе участвуют как минимум две стороны, и у каждой своя роль. Внутри приложения работает клиентская библиотека: она хранит числа в памяти программы и по запросу выдаёт их в виде текста. Для Python это библиотека prometheus-client. Отдельной программой работает сервер Prometheus: он запрашивает числа, хранит их историю, отвечает на запросы и показывает веб-интерфейс.

Две части, которые нужны в этом модулекто начинает обмен
внутри приложенияКлиентская библиотекахранит числа и отдаёт их текстом
отдельная программаСервер Prometheusзапрашивает, хранит, отвечает

Стрелка на схеме направлена от сервера к приложению: обмен начинает сервер, а приложение только отвечает. Почему сделано так, объясняет глава 2.5.

Кроме этих двух частей, есть ещё четыре программы. В модуле они не используются, но их названия встречаются в документации, поэтому они перечислены здесь. Exporter показывает числа чужой программы, код которой изменить нельзя: PostgreSQL, Redis, операционной системы. Pushgateway принимает числа от коротких задач, которые завершаются раньше очередного опроса. Alertmanager рассылает оповещения, которые вычислил сервер. Grafana — отдельный продукт другой компании, он строит графики по данным Prometheus.

Что внутри сервера

Сервер тоже состоит из частей. Их пять, и данные проходят через них в том же порядке, в каком в §1 шли три действия: сбор, хранение, запросы.

  1. Список адресов. Сервер читает файл prometheus.yml и узнаёт, какие программы опрашивать.
  2. Сбор. Для каждого адреса сервер раз в интервал отправляет HTTP-запрос и разбирает ответ.
  3. TSDB. База временных рядов на диске сервера. Сюда записываются отсчёты.
  4. PromQL. Часть сервера, которая выполняет запросы к сохранённым рядам.
  5. Веб-интерфейс и HTTP API. Через них запросы отправляют человек и другие программы, например Grafana.
Подробнее: как TSDB хранит данные на диске

Новые отсчёты попадают в память сервера и одновременно в журнал на диске. Журнал называется WAL (write-ahead log). По нему сервер восстанавливает данные после перезапуска. Раз в два часа накопленные отсчёты записываются в отдельный блок на диске, который больше не меняется. По умолчанию данные хранятся 15 дней.

Содержимое папки с данными в контейнере стенда. Сервер работал меньше двух часов, поэтому блоков ещё нет:

docker compose exec prometheus ls /prometheusстенд модуля
chunks_head
lock
queries.active
wal

wal — журнал, chunks_head — файлы с отсчётами из памяти. Файл lock запрещает второму серверу открыть ту же базу.

У каждого сервера Prometheus своя база. По документации, локальное хранилище не объединяется в кластер и не копируется на другие серверы. Так сервер не зависит от соседних систем и продолжает работать, когда они недоступны. Для долгого хранения Prometheus передаёт данные в отдельные системы.

Части названы по отдельности. В следующем разделе они работают вместе: одно число проходит через все пять.

§6Путь одного числа

Все понятия главы теперь можно собрать в одну цепочку. Для этого схема ниже ведёт одно число от момента, когда оно появилось в коде, до момента, когда его увидел человек. Это число 125: столько запросов GET со статусом 200 обработало приложение стенда.

В цепочке пять этапов. На первом число находится в памяти приложения, на втором становится строкой текста, на третьем его забирает сервер, на четвёртом оно попадает в базу, на пятом возвращается в ответе на запрос. Все строки на схеме взяты со стенда. Нажимайте на этапы по порядку или на кнопку «далее».

Приложение → /metrics → Prometheus → TSDB → PromQLпуть данных

Число в памяти программы

Приложение обработало запрос и увеличило счётчик на единицу. Число находится в памяти программы. Prometheus и диск в этом шаге не участвуют.

HTTP_REQUESTS.labels("GET", "200").inc()   # было 124, стало 125

После перезапуска программы счётчик начнётся с нуля. Библиотека его нигде не сохраняет.

Число в виде строки текста

Приложение получило запрос GET /metrics. Библиотека записала все счётчики в виде текста. Одна строка — один ряд: имя, метки, значение.

# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 125.0
http_requests_total{method="GET",status="404"} 3.0
http_requests_total{method="POST",status="405"} 1.0

В тексте только текущие значения. Истории у приложения нет.

Сервер забирает текст и добавляет свои метки

Раз в 15 секунд Prometheus отправляет запрос GET http://api:8000/metrics. К каждому ряду из ответа он добавляет две метки: job — название задания из своих настроек, instance — адрес приложения.

http_requests_total{method="GET",status="200"} 125.0
          ↓  + job="api", instance="api:8000", время начала сбора
http_requests_total{instance="api:8000",job="api",method="GET",status="200"}

Ещё сервер записывает несколько своих рядов о самом опросе. Один из них — ряд up из §4.

Отсчёт в базе

База TSDB находит ряд с таким именем и метками и дописывает в него новый отсчёт: время и значение. Если такого ряда ещё нет, база его создаёт.

http_requests_total{instance="api:8000",job="api",method="GET",status="200"}
  13:22:07  125
  13:22:22  125
  13:22:37  125

Ответ на запрос

В веб-интерфейсе введён запрос http_requests_total. Сервер нашёл все ряды с этим именем и показал последнее значение каждого.

Вкладка Query в Prometheus: запрос http_requests_total, три ряда со значениями 125, 3 и 1
Query → Table: три ряда. Метки instance и job добавил Prometheus

Остальные главы модуля идут по этой схеме слева направо. Глава 2.2 объясняет, откуда сервер берёт адрес api:8000. Глава 2.3 разбирает правила, по которым записан текст на этапе 2. Глава 2.4 посвящена самому опросу на этапе 3, а глава 2.5 — тому, почему запрос идёт от сервера к приложению. В главе 2.6 вся цепочка запускается на вашем компьютере.

Схема показывает, что Prometheus делает. Последний раздел главы показывает, для каких задач этого недостаточно.

§7Границы применения

На пути числа есть место, где данные могут потеряться. Приложение увеличило счётчик, а до следующего опроса программа аварийно завершилась. Значение было только в её памяти, и Prometheus его не получил. Такая потеря заложена в устройство системы: Prometheus проще и надёжнее работает во время сбоев, но не обещает, что учтёт каждое событие.

Это похоже на спидометр и чек на заправке. Спидометр показывает скорость приблизительно и работает всё время поездки. Чек точен до копейки. Скорость смотрят по спидометру, деньги считают по чекам.

Из этого получается правило выбора. Prometheus подходит, когда нужно число с историей и небольшая неточность допустима. Пример: заметить, что после обновления сервиса выросла доля ошибок, и получить оповещение. Доля ошибок — число, и Prometheus сравнит значения до обновления и после него.

Prometheus не подходит в двух случаях. Первый — точный учёт: посчитать запросы каждого клиента и выставить счёт. Часть событий теряется при падении программы, а метка с идентификатором клиента создаёт по ряду на каждого клиента. Документация приводит этот пример и советует для него другие системы. Второй случай — поиск одного события: найти запрос, который вернул ошибку, и его параметры. Метрика хранит количество ошибок, а параметры запроса есть в логах и трассах.

§8Проверьте себя

Вопрос 1В приложении одна метрика http_requests_total с метками method и status. Встретились сочетания GET 200, GET 404, POST 405. Сколько временных рядов хранит Prometheus для этой метрики с одного экземпляра приложения?

  • Ряд определяется именем и всеми метками. Имя одно, наборов меток три.

  • Верно. Каждое сочетание method и status — отдельный ряд. Метки job и instance у всех трёх одинаковые и числа рядов не меняют.

  • Так растёт объём лога. Число рядов от числа запросов не зависит: запросы меняют только значения.

Вопрос 2Где хранится история значения http_requests_total?

  • Библиотека хранит только текущее значение. Страница /metrics показывает одно число на ряд.

  • Верно. История появляется на сервере: отсчёт за отсчётом, с отметкой времени начала опроса.

  • WAL — журнал сервера Prometheus. Приложение метрики на диск не пишет.

Вопрос 3Какую задачу документация Prometheus приводит как неподходящую?

  • Для таких сервисов Prometheus подходит: документация называет это его сильной стороной.

  • По документации, Prometheus рассчитан на работу во время сбоя.

  • Верно. Для учёта со стопроцентной точностью собранные данные недостаточно полны.

Вопрос 4Почему в метку не записывают идентификатор пользователя?

  • Значение метки — строка. Числом бывает только значение отсчёта.

  • Верно. Каждый ряд занимает память сервера. В метки записывают значения из небольшого набора.

  • Такого правила нет. Ограничения на длину меток настраиваются отдельно и по умолчанию выключены.

Источники главы
  1. Prometheus. Overview — prometheus.io/docs/introduction/overview
  2. Prometheus. Data model — prometheus.io/docs/concepts/data_model
  3. Prometheus. FAQ — prometheus.io/docs/introduction/faq
  4. Prometheus. Storage — prometheus.io/docs/prometheus/latest/storage
  5. Стенд модуля: Prometheus 3.5.0, prometheus-client 0.26.0; запросы выполнены 29.09.2026
Метрики и наблюдаемость · Модуль 2 · Как работает Prometheus Автор: Макаров Максим Николаевич