Prometheus: или как не утонуть в метриках
Введение: почему PromPull — это не просто слово, а философия
Prometheus не просто собирает метрики — он меняет парадигму мониторинга. В отличие от традиционных пуш-систем (Zabbix, Nagios), где агент сам отправляет данные на сервер, Prometheus работает по принципу pull: сервер сам запрашивает метрики у целей (targets) по HTTP-эндпоинту /metrics. Это кажется простым, но на практике приводит к трем ключевым проблемам:
- Латентность обнаружения проблем — если цель падает, Prometheus не узнает об этом сразу, пока не истечет таймаут запроса (по умолчанию 1 минута).
- Нагрузка на цели — если у вас тысячи микросервисов, каждый из которых генерирует сотни метрик, то даже при оптимизированном polling нагрузка может стать критической.
- Управление состоянием — в pull-системе состояние цели определяется не сервером, а клиентом. Это значит, что если ваш сервис перестал отвечать, Prometheus не знает об этом, пока не получит таймаут.
Вывод: Prometheus — это не просто инструмент, а система, требующая правильной настройки и понимания trade-offs. Если вы просто развернете его "из коробки", вы получите либо ложное чувство безопасности (метрики есть, но они не отражают реальное состояние), либо производительность, падающую под нагрузкой.
Проблема: когда Prometheus становится камнем на шее
Мы видели проекты, где Prometheus:
- Заедал CPU на 90%+ из-за неоптимизированных запросов к Thanos или Cortex.
- Падало под нагрузкой из-за неверно настроенного
scrape_configs(например, слишком частый polling для тяжелых целей). - Генерал метрик в миллиарды точек, из-за чего PromQL-запросы выполнялись по 30 секунд.
- Не обнаруживал критических ошибок из-за неверно настроенных alertmanager-ов.
Причина почти всегда одна: отсутствие понимания, что Prometheus — это не только сам сервер, а экосистема, включающая:
- Цели (
targets) с правильно экспортируемыми метриками. - Scrape-конфигурации с учетом латентности и нагрузки.
- Storage (Prometheus сам по себе хранит данные только 15 дней, дальше нужны Thanos, Cortex или VictoriaMetrics).
- Alerting с правильно настроенными правилами и тишиной (
silences). - Visualization (Grafana, но не только — иногда проще писать свои дашборды на PromQL+Python).
Практика: как не завалить Prometheus на старте
1. Настройка scrape-конфигураций: не все цели равны
Ошибка №1: Одинаковый интервал polling для всех целей. Решение: Настройте разные интервалы в зависимости от типа цели:
- Легкие сервисы (API-гейты, кэши) —
15s. - Тяжелые БД (PostgreSQL, MongoDB) —
60s. - Микросервисы с высокой латентностью —
30s. - Системные метрики (node_exporter) —
15s.
Пример конфига prometheus.yml для разных типов целей:
scrape_configs:
- job_name: 'api_gateway'
scrape_interval: 15s
static_configs:
- targets: ['api-gateway-1:8080', 'api-gateway-2:8080']
- job_name: 'database'
scrape_interval: 60s
static_configs:
- targets: ['postgres-master:5432', 'postgres-replica:5432']
- job_name: 'system_metrics'
scrape_interval: 15s
static_configs:
- targets: ['node-exporter-1:9100', 'node-exporter-2:9100']
Лайфхак: Используйте scrape_timeout (по умолчанию scrape_interval), но уменьшайте его для тяжелых целей. Например, если polling идет каждые 60 секунд, а цель отвечает за 45 секунд, оставьте scrape_timeout: 55s, чтобы избежать накопления задержек.
2. Метрики: не все равны, и их нужно фильтровать
Ошибка №2: Сбор всех метрик без фильтрации.
Решение: Используйте metric_relabel_configs для отсеивания ненужного шума.
Пример: Отфильтруйте метрики process_* для легких сервисов, оставив только критические:
scrape_configs:
- job_name: 'light_service'
scrape_interval: 15s
metric_relabel_configs:
- source_labels: [__name__]
regex: 'process_.*'
action: drop # Убираем все process-метрики
static_configs:
- targets: ['light-service:8080']
Еще один лайфхак: Используйте relabel_configs для добавления дополнительных меток (labels), чтобы группировать цели по типам:
relabel_configs:
- source_labels: [__address__]
target_label: env
regex: '(.*)\.example\.com'
replacement: '$1'
3. Storage: Prometheus один не вытянет
Ошибка №3: Хранение данных только в Prometheus (максимум 15 дней). Решение: Используйте Thanos или VictoriaMetrics для долговременного хранения.
Пример конфига Thanos для Prometheus:
global:
scrape_interval: 15s
evaluation_interval: 15s
storage:
tsdb:
path: /prometheus/data
thanos:
object_storage_config_file: /etc/prometheus/thanos.yaml
rule_files:
- /etc/prometheus/rules/*.yaml
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
Конфиг Thanos для S3:
type: S3
config:
bucket: "my-prometheus-bucket"
endpoint: "s3.example.com"
access_key: "AKIA..."
secret_key: "secret"
insecure: true
Важно: Настройте компактность (compaction) в Thanos, чтобы избежать взрыва хранилища:
compaction:
level: "monthly"
max_compaction_segment_duration: "30d"
Примеры: как не завалить PromQL-запросы
Пример 1: Запрос, который убивает производительность
Плохой запрос (сканирует все метрики):
sum(rate(http_requests_total[5m])) by (service)
Проблема: Если у вас 1000 сервисов и каждая метрика экспортируется в 10 вариантах (status, method, path), то запрос может обработать миллионы временных серий.
Решение: Уже на уровне экспорта фильтруйте метрики или используйте record для предварительной агрегации:
# В rules.yml
groups:
- name: aggregation
rules:
- record: job:http_requests_total:rate5m
expr: sum(rate(http_requests_total[5m])) by (job, service)
Пример 2: Правильное использование group_left и group_right
Задача: Найти долю ошибок по сервисам.
Плохой запрос (теряет контекст):
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
Решение: Используйте group_left для сохранения контекста:
sum by (service) (
rate(http_requests_total{status=~"5.."}[5m])
) /
sum by (service) (
rate(http_requests_total[5m])
)
Типичные ошибки и как их избежать
| Ошибка | Причина | Решение |
|---|---|---|
| Prometheus падает под нагрузкой | Слишком частый polling тяжелых целей | Увеличьте scrape_interval, добавьте scrape_timeout |
| Alertmanager шлет дубликаты | Неправильно настроенные group_by в alert rules |
Используйте group_by: [alertname, cluster] |
| Метрики не обновляются | Целевой сервис не экспортирует /metrics |
Проверьте targets, логи сервиса, сетевые правила |
| PromQL-запросы висят 30+ секунд | Слишком много временных серий | Фильтруйте метрики на уровне экспорта, используйте record |
| Thanos съедает весь диск | Не настроена компактизация | Настройте compaction в thanos.yaml |
| Ложные тревоги | Неправильные условия в alert rules | Используйте for и unless, тестируйте в Grafana |
Вывод: как сделать Prometheus полезным, а не обузой
- Настройте scrape-конфигурации под реальные нужды — не все цели должны поллиться одинаково часто.
- Фильтруйте метрики на уровне экспорта — не собирать все, что можно собрать.
- Используйте долговременное хранилище (Thanos/VictoriaMetrics) — Prometheus один не справится с длительным ретеншном.
- Оптимизируйте PromQL-запросы — не пишите запросы, которые сканируют миллионы серий.
- Настраивайте alerting правильно — используйте
group_by,for,unless, и тестируйте правила в Grafana перед развертыванием. - Мониторьте сам Prometheus — следите за
prometheus_target_scrapes_total,prometheus_tsdb_head_series,prometheus_tsdb_wal_flushes_total.
Финальный совет: Prometheus — это не "развернул и забыл". Это живая система, которая требует:
- Регулярной оптимизации (чистка ненужных метрик, настройка интервалов).
- Тестирования (проверяйте alert rules в Grafana, а не в продакшене).
- Документирования (какие метрики критические, какие — информационные).
Если вы сделаете это правильно, Prometheus станет одним из самых полезных инструментов в вашем стеке. Если нет — он превратится в черную дыру метрик, которая съедает ресурсы и не дает никакой ценной информации.