Модуль 2 · как работает prometheus · сбор метрик
Глава 2.8
Итоги модуля:
главное коротко
В этой главе собрано главное из глав модуля. На каждую главу отведён один раздел: несколько фраз о сути и один пример со стенда. Новых понятий здесь нет. Глава нужна, чтобы повторить модуль перед тестом и быстро найти нужное место в подробных главах.
- Категория
- Повторение
- Уровень
- После глав 2.1–2.7
- Опирается на
- Весь модуль 2
- Результат
- Путь числа от приложения до запроса — по памяти
§1Что делает Prometheus
Prometheus — программа-сервер, которая делает три вещи по порядку: забирает у программ числа, сохраняет их вместе с временем и отвечает на запросы по сохранённому. Числа называются метриками. Метрика хранит количество или величину по группе событий, а подробности отдельного события остаются в логах.
Сохранённые значения одной величины образуют временной ряд. Ряд определяется именем метрики и всеми метками сразу, поэтому у одной метрики рядов столько, сколько встретилось сочетаний меток.
Из этого следует ограничение на метки. Каждое новое значение метки создаёт новый ряд, поэтому в метки записывают значения из небольшого набора: метод, код ответа. Идентификатор пользователя или запроса в метку не записывают. Второе ограничение: часть событий может потеряться при остановке программы, поэтому для точного учёта, например для счетов, Prometheus не подходит.
Подробно: глава 2.1. Чтобы забрать числа, серверу нужен адрес программы.
§2Target: адрес
Target — адрес, по которому Prometheus запрашивает метрики. В настройках записывают только хост и порт. Протокол http:// и путь /metrics подставляются сами и меняются параметрами scheme и metrics_path.
scrape_configs: - job_name: api static_configs: - targets: ['api:8000']
К каждому числу этого target Prometheus добавит две метки. Метка job равна названию задания: это сервис в целом. Метка instance равна адресу: это одна копия сервиса.
Адрес записывают таким, каким он доступен из места, где запущен Prometheus. На стенде у одного приложения три адреса, и подходит тот, который соответствует месту запуска.
| Где запущен Prometheus | Адрес target |
|---|---|
| В одной сети Compose с приложением | api:8000 |
| На компьютере, без Docker | localhost:8020 |
| В контейнере вне сети приложения | host.docker.internal:8020 |
Частая ошибка — записать localhost для Prometheus в контейнере. Для него localhost — его собственный контейнер, и запрос заканчивается ошибкой connection refused.
Подробно: глава 2.2. По адресу находится страница с числами.
§3Страница /metrics
Страница /metrics — обычный текст с текущими значениями метрик. Приложение никому его не отправляет: Prometheus, браузер и curl получают один и тот же ответ. Меток job и instance и времени в нём нет, их добавляет Prometheus.
# HELP http_requests_total Total HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 125.0
Строка значения состоит из трёх частей: имя метрики, метки в фигурных скобках, число. Строка HELP содержит описание, строка TYPE — тип. Типов четыре, и чаще других встречаются три: counter только растёт, gauge меняется в обе стороны, histogram хранит набор счётчиков-корзин.
Формат проверяется строго в одном отношении. Ошибка записи в одной строке — значение метки без кавычек или запятая в числе — означает, что отклонён весь ответ. То же происходит при неправильном заголовке Content-Type: Prometheus 3 такой ответ не читает.
Подробно: глава 2.3. Адрес и страницу соединяет действие — опрос.
§4Scrape: опрос
Scrape — один запрос Prometheus к target вместе с обработкой ответа. У него две настройки. scrape_interval задаёт, как часто повторять опрос; на стенде это 15 секунд. scrape_timeout задаёт, сколько ждать ответа; по умолчанию 10 секунд, и он не может быть больше интервала.
Между двумя опросами данные теряются по-разному. Gauge показывает значение в момент опроса, и всплеск между опросами пропадает. Counter накапливает события в приложении, и следующий опрос получает их сумму. Поэтому события считают счётчиками.
После каждого scrape Prometheus сам записывает ряд up: 1, если опрос удался, и 0, если нет. По нему видно, что target недоступен, а причину сообщает начало текста ошибки.
| Слова в тексте ошибки | Что произошло |
|---|---|
dial tcp … connection refused | По адресу никто не отвечает |
context deadline exceeded | Ответ не пришёл за время timeout |
HTTP status 404 | Неверный путь |
unsupported Content-Type | Неверный заголовок ответа |
… while parsing | Ошибка записи в строке метрики |
Пример того, что остаётся в базе. Приложение стенда остановили на 50 секунд, затем запустили и отправили 30 запросов.
Ряд up записан и во время остановки. Ряд приложения прерван сразу. После запуска счётчик начался заново: 30 вместо 155, потому что число хранилось в памяти программы.
Подробно: глава 2.4. Во всех этих шагах обмен начинал сервер, и у этого порядка есть название.
§5Pull и push
Числа можно доставить двумя способами. При pull обмен начинает сервер: он опрашивает приложения по списку. Так работает Prometheus. При push обмен начинает приложение: оно отправляет числа на сервер по своему расписанию.
Различие проявляется, когда приложение останавливается. При pull сервер получает ошибку и записывает up = 0: известно, какой адрес не ответил и с какого момента. При push сервер ничего не получает и не может отличить остановленное приложение от приложения без новых данных.
У pull есть ограничение: короткая задача может завершиться раньше очередного опроса. Пример — скрипт резервного копирования, который работает 40 секунд при интервале 60. Для таких задач есть Pushgateway: задача отправляет в него результат, а Prometheus опрашивает Pushgateway как обычный target. Для программ, которые работают постоянно, Pushgateway не используют: у них пропадает свой ряд up.
Подробно: глава 2.5. Последняя глава — запуск на своём компьютере.
§6Запуск стенда
Стенд состоит из двух контейнеров в одной сети Docker Compose: приложение FastAPI и Prometheus. Весь запуск — четыре действия.
docker compose up -d --build # запустить оба контейнера curl http://localhost:8020/items/1 # отправить запрос к приложению curl http://localhost:8020/metrics # посмотреть числа # браузер: http://localhost:9092 → Status → Target health → состояние UP
В приложении счётчик увеличивается в одной общей функции, через которую проходит каждый запрос, и запросы самого Prometheus к /metrics в нём не учитываются. В веб-интерфейсе Prometheus достаточно двух запросов: up показывает, доступен ли target, а http_requests_total — ряды счётчика. Число в таблице обновляется после очередного scrape, то есть не позже чем через 15 секунд.
Если target не в состоянии UP, порядок проверки такой: запущены ли контейнеры (docker compose ps), какой текст ошибки на странице Target health, какой адрес записан в targets.
Подробно: глава 2.6. Формат файла настроек и ряд up собраны в главе 2.7. В последнем разделе термины модуля собраны в одну таблицу.
§7Термины модуля одной строкой
| Термин | Что это | Пример |
|---|---|---|
| Метрика | Число, которое программа считает о себе и показывает по запросу | http_requests_total |
| Метка | Пара «название — значение», которая уточняет, о чём число | status="404" |
| Временной ряд | Сохранённые значения одной величины с временем | Значения up раз в 15 секунд |
| Counter | Число, которое только растёт | Обработанные запросы |
| Gauge | Число, которое растёт и уменьшается | Длина очереди |
| Target | Адрес, по которому запрашивают метрики | api:8000 |
| Job | Группа target с одним назначением | job="api" |
| Instance | Один target, обычно одна программа | instance="api:8000" |
| Scrape | Один опрос одного target | GET /metrics раз в 15 секунд |
| up | Ряд, который Prometheus пишет после каждого scrape | 1 — удался, 0 — нет |
| YAML | Формат файла настроек: вложенность отступом из пробелов, списки через «-» | scrape_interval: 15s |
| Pull | Обмен начинает сервер | Prometheus |
| Push | Обмен начинает приложение | Задача → Pushgateway |
Весь модуль укладывается в одну цепочку: приложение считает число, страница /metrics показывает его текстом, Prometheus по адресу target забирает текст при scrape, добавляет метки и время и записывает в базу, а запрос возвращает сохранённое.