Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Инструментирование приложения метриками Prometheus

Метрики Prometheus в приложении: counters, histograms и что измерять

Как инструментировать Python-приложение метриками: типы метрик Prometheus, RED-подход, гистограммы против средних, лейблы и их кардинальность, /metrics-эндпоинт — практический минимум.

Прямой ответ

Инструментирование приложения — это не «поставить счётчик на всё», а четыре метрики на сервис по RED-подходу: Rate (запросов в секунду), Errors (доля ошибок), Duration (распределение длительностей — гистограмма, не среднее) — плюс ресурсные (очереди, пул соединений, размер кеша). Технически в Python это prometheus-client: декоратор/мiddleware на HTTP-слой, явные counters/histograms на ключевых бизнес-операциях, и /metrics-эндпоинт, который Prometheus опрашивает раз в 15–30 с (pull-модель). Два правила, которые отличают полезные метрики от шума: гистограмма вместо среднего (средняя латентность 80 мс при p99 в 4 с — ложь во спасение, которую видят только ваши пользователи) и низкая кардинальность лейблов (user_id в лейбле — способ убить Prometheus; лейбл — это измерение с десятком значений, не идентификатор).

Типы метрик: какой и когда

Четыре примитива покрывают всё. Counter — монотонный счётчик (число запросов, ошибок, отправок писем); сам по себе бесполезен, полезен через rate() в запросах (рост в секунду); сброс процесса обнуляет counter — rate() это переживает. Gauge — значение «сейчас» (размер очереди, активные соединения, температура) — может расти и падать; для «длины очереди» gauge честнее counter'а. Histogram — распределение значений по бакетам (длительности запросов, размеры ответов): на сервере считается квантиль histogram_quantile(0.95, ...) по агрегированным бакетам; бакеты задаются осознанно под SLA (0.05/0.1/0.25/0.5/1/2.5/5/10 с — вокруг целевой латентности, а не «по дефолту»). Summary — квантили на клиенте (нельзя агрегировать между инстансами — почти всегда histogram правильнее). Именование — конвенция Prometheus: namespace_subsystem_name_unit (http_requests_total, http_request_duration_seconds) — консистентные имена делают PromQL-запросы переносимыми между сервисами.

RED для HTTP-сервиса: middleware вместо ручной обвязки

Полноценное покрытие HTTP-слоя — один middleware (или готовый из prometheus-client/FastAPI-интеграций): на каждый запрос — инкремент http_requests_total{method, path, status} (path — нормализованный шаблон /orders/{id}, не конкретный /orders/42 — иначе кардинальность взрывается), observe в http_request_duration_seconds{method, path}, и gauge активных запросов. Три метрики, три запроса PromQL — и у сервиса есть R (rate по всем/по статусам), E (доля 5xx), D (p50/p95/p99 по путям). Точка входа мониторинга для любого сервиса на этом заканчивается как «минимум обязательного»; всё остальное инструментирование — бизнес-специфично и добавляется по инцидентам и вопросам («а сколько заказов падает на валидации?» — если метрики нет, ответ «не знаем» до следующего релиза).

Бизнес-метрики и ресурсные gauge

Второй слой — доменные счётчики: orders_created_total, payments_failed_total{reason}, emails_sent_total — счётчики событий, которые важны продукту (и которые алертят раньше инфраструктурных: «оплаты упали до нуля» видно по бизнес-метрике, когда CPU и латентность ещё в норме). Третий — ресурсные gauge: размер очереди задач (queue_depth — растущая очередь при стабильном rate поступления — деградация воркеров), использование пула соединений БД (80% пула стабильно — скоро таймауты), hit-rate кеша (counters hits/misses — ratio в запросе; паттерны кеширования без метрик — гадание). Правило добавления: каждая метрика должна отвечать на вопрос, который уже задавали («сколько?», «как быстро?»); метрики «на всякий случай» — стоимость хранения и шума без пользы.

Лейблы и кардинальность: главная ловушка

Каждая комбинация значений лейблов — отдельная временная серия: лейблы {method(4), path(30), status(8)} — ~1000 серий на метрику — нормально; добавить user_id (миллион значений) — Prometheus умирает (память, индексация). Правило: лейбл — измерение с ограниченным, известным заранее множеством значений (методы, шаблоны путей, типы ошибок, окружения); идентификаторы сущностей, email'ы, конкретные URL с параметрами — никогда. Вторая ловушка — динамические path-шаблоны без нормализации (/user/12345 вместо /user/{id}) и лейблы с ошибками в значениях («ошибка: текст исключения» — текст бесконечно вариативен; тип/код ошибки — ограничен). Оценка кардинальности — prometheus_tsdb_head_series на сервере и count by (__name__)({__name__=~".+"}) — топ метрик по сериям показывает виновников до инцидента.

Практический сценарий: инструментирование FastAPI-сервиса

Полный минимум за час работы. Подключение: prometheus-client + /metrics-роут (generate_latest()) на внутреннем порту (или за auth — метрики содержат структуру трафика и не должны быть публичны). HTTP-слой: middleware с counter/histogram/active-gauge по схеме выше (для FastAPI есть готовые middleware — проверить, что path нормализуется по роутам, а не по raw-URL). Бизнес-слой: counter оплат с лейблом результата, counter созданных заказов. Ресурсы: gauge глубины Celery-очереди (обновляется фоновой задачей или читается из Redis при scrape), gauge пула SQLAlchemy (pool.checkedout()). Проверка локально: curl localhost:8000/metrics — метрики видны; PromQL-запросы rate(http_requests_total[5m]), histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, path)) в Grafana (дашборды). Итог: локальный prometheus из dev-стека видит сервис, и первый же нагрузочный прогон (locust) даёт картину p95 по путям без единого «print в лог и глазеть».

FAQ

Сколько метрик — много? Ориентир — десятки метрик на сервис при умеренной кардинальности; сотни серий на метрику — повод пересмотреть лейблы. Стоимость серии — память TSDB и время запросов; «измеряем всё» превращает мониторинг в проблему.

Histogram-бакеты: как выбрать? Вокруг SLA и ожидаемого распределения: если цель p95 < 300 мс, бакет 0.3 обязателен (квантиль точнее, когда граница SLA совпадает с границей бакета). Дефолтные бакеты prometheus-client — разумный старт, корректируются после первых недель данных.

Метрики или логи? Метрики — агрегаты для трендов и алертов (дешёвые, всегда-on); логи — детали конкретного события (дорогие, по запросу). «Считать ошибки по логам через grep» — антипаттерн: счётчик ошибок — метрика; «почему именно этот запрос упал» — лог с request_id (структурированные логи).

Pushgateway нужен? Только для короткоживущих процессов (cron-джобы, batch-скрипты), которые не доживают до scrape: джоб пушит метрики в Pushgateway, Prometheus забирает оттуда. Для долгоживущих сервисов — только прямой pull; Pushgateway как постоянный посредник — антипаттерн (скрывает живость сервиса).

Источники: документация Prometheus (client libs, instrumentation practices, naming) — ссылки в шапке.