Пара 20: Prometheus: сбор метрик и PromQL
90 минут · 3 курс, ML.
Содержание и результат
Поднять Prometheus, проверить target и построить rate и p95 из метрик StudyPulse.
План занятия
0–10: контекст и исходная задача. 10–40: устройство и механизмы. 40–55: демонстрация команд. 55–80: лабораторная работа. 80–90: разбор результата и фиксация исправлений.
Практика выполняется в своей учебной папке и на localhost. Подготовка окружения описана в lab/README.md.
Pull и временные ряды
Prometheus периодически читает endpoint метрик.
Приложение предоставляет /metrics в формате экспозиции. Prometheus по расписанию делает scrape и сохраняет samples с именем метрики, labels и временем. up показывает успешность scrape, но up=1 ещё не означает правильный predict. Targets помогают отличить ошибку сбора от отсутствия пользовательского трафика. В учебном compose target app:8000 доступен по внутренней сети; Prometheus UI публикуется только на localhost:9090. Интервал 5 секунд удобен для демонстрации, а не универсальная настройка production. Первые rate-запросы требуют нескольких наблюдений.
Аналогия: дежурный регулярно переписывает показания счётчика.
Counter, gauge, histogram
Тип метрики определяет корректную операцию.
Counter накапливает события и сбрасывается при рестарте; rate считает скорость с учётом сбросов. Gauge показывает текущее значение, например активные запросы. Histogram распределяет длительности по накопительным bucket и хранит count/sum. Для средней длительности делим rate(sum) на rate(count); для p95 используем histogram_quantile с rate bucket. p95 — оценка границы, ниже которой находится около 95% наблюдений, а не максимальное время. При малом числе событий оценка нестабильна. Наш текстовый histogram учебный и потокобезопасный, в рабочем проекте обычно берут официальный client.
Аналогия: одометр, спидометр и распределение длительностей поездок.
Labels и кардинальность
Каждая уникальная комбинация labels создаёт отдельный ряд.
route=/predict и status=200 имеют ограниченное множество значений. request_id, email и произвольный URL в label создают огромное число рядов и могут раскрыть данные. В учебном приложении неизвестные пути нормализуются в route=other. Request ID оставляем в логе, не в метриках. Это не косметическое правило: число рядов влияет на память, хранение и скорость запросов. Не добавляйте label только потому, что поле существует в запросе.
Аналогия: отдельная папка на каждую категорию удобна, на каждую песчинку — нет.
Команды и наблюдения
Окружение: Ubuntu / Bash, lab; PromQL в UI :9090.
docker compose -f compose.yaml -f compose.monitoring.yaml up -d
python3 scripts/load.py --requests 60 --concurrency 3
# PromQL expressions
up{job="studypulse"}
sum(rate(studypulse_http_requests_total{route="/predict"}[1m]))
histogram_quantile(0.95, sum by (le) (rate(studypulse_request_duration_seconds_bucket{route="/predict"}[1m])))
Команды PromQL вводятся в интерфейсе Prometheus, не в Bash. Трафик ограничен своим localhost.
Ожидаемый результат: Target UP; rate появляется после нескольких scrape; p95 возвращается при наличии достаточных наблюдений.
Вариант для macOS
Prometheus и PromQL одинаковы в контейнерном варианте. Если нужный учебный image не поддерживает архитектуру, проверьте manifest и используйте согласованную платформу/VM, а не случайную подмену версии.
docker compose -f compose.yaml -f compose.monitoring.yaml up -d
python3 scripts/load.py --requests 60 --concurrency 3
Практика: Из счётчика в график
- Откройте Targets и проверьте app:8000.
- Выполните ограниченную нагрузку; подождите 15–30 секунд.
- Сравните значение counter, rate и p95 в PromQL.
- Перезапустите app и объясните сброс счётчика без объявления отрицательной скорости.
Результат: Три запроса PromQL с интерпретацией, а не только скриншоты.
Проверка: Единицы подписаны; request_id отсутствует в labels; up не подменяет smoke-test.
Неисправность для разбора: Выражение rate без данных воспринимают как ошибку приложения.
Решение и диагностика
Проверьте target, затем сырой /metrics, затем окно времени. После рестарта rate учитывает reset, но короткое окно и редкий трафик дадут нестабильный график. Для p95 сохраняется label le: sum by (le)(rate(...bucket[1m])). Ошибки сервера: sum(rate(studypulse_http_requests_total{route="/predict",status=~"5.."}[1m])) / sum(rate(studypulse_http_requests_total{route="/predict"}[1m])). При нулевом трафике отношение не имеет информативного значения.
Основные выводы
- Он накопительный; нужна скорость изменения за окно.
- Высокая кардинальность и ненужное раскрытие идентификаторов.
Самостоятельная работа
Подготовить два PromQL-запроса и объяснить их единицы и условия интерпретации.