Как выбрать интервалы опроса метрик и не перегрузить систему мониторинга

10 минут чтения
Средний рейтинг статьи — 4.8

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

Поэтому интервал опроса — это всегда компромисс, и решается он не одним значением в global, а по группам метрик. Разберём, из чего складывается стоимость интервала, какие границы задаёт сам Prometheus и как менять частоту осознанно.

Почему нельзя опрашивать всё каждую секунду

Каждый цикл опроса — это запрос к экспортёру, его работа по сбору данных, трафик и запись в хранилище. Пока метрик десятки, это незаметно. Проблема в том, что стоимость растёт по произведению: количество серий × частота.

Уменьшение интервала с 60 до 5 секунд не «немного увеличивает» объём данных, а увеличивает его в двенадцать раз — при том же количестве серий. Узким местом при этом становится сама система мониторинга, и обычно это выясняется в худший момент: во время инцидента, когда Prometheus не отвечает на запросы, потому что занят приёмом данных.

Посмотреть, сколько сэмплов в секунду принимает ваш Prometheus прямо сейчас, можно у него же:

rate(prometheus_tsdb_head_samples_appended_total[5m])
prometheus_tsdb_head_series

Первое — темп приёма, второе — количество активных серий. Эти два числа и есть то, чем вы управляете, выбирая интервалы.

Считаем стоимость интервала в байтах

Место в хранилище считается по простой формуле из документации Prometheus:

объём = время хранения × сэмплов в секунду × байт на сэмпл

После сжатия один сэмпл в TSDB занимает примерно 1–2 байта. Возьмём 10 000 серий:

ИнтервалСэмплов в секундуВ суткиЗа 30 дней хранения
15 с~667~115 МБ~3,4 ГБ
30 с~333~58 МБ~1,7 ГБ
60 с~167~29 МБ~0,9 ГБ

Числа сами по себе небольшие — важна пропорция. Учетверив частоту, вы учетверяете и диск, и объём работы при каждом запросе за длинный период: график за месяц на 15-секундной сетке — это в четыре раза больше точек, которые нужно прочитать и сжать в пиксели.

Ограничения хранения задаются флагами, и лучше выставить оба:

prometheus \
  --storage.tsdb.retention.time=30d \
  --storage.tsdb.retention.size=50GB

retention.size — страховка: он не даст диску закончиться, если количество серий внезапно вырастет после неудачного релиза с высокой кардинальностью.

Разным метрикам — разные интервалы

Самая частая ошибка — один интервал в global на все джобы. Между тем частоту можно задать для каждого джоба отдельно, и именно так и стоит делать:

global:
  scrape_interval: 60s
  evaluation_interval: 60s
 
scrape_configs:
  # Время ответа, RPS и ошибки — по ним строятся алерты, нужна реакция
  - job_name: 'api'
    scrape_interval: 15s
    scrape_timeout: 10s
    static_configs:
      - targets: ['api-1:9090', 'api-2:9090']
 
  # Базовые метрики хоста: всплески видны и на 30-секундной сетке
  - job_name: 'node'
    scrape_interval: 30s
    static_configs:
      - targets: ['node-1:9100', 'node-2:9100']
 
  # Тяжёлый экспортер: каждый скрейп — это реальные запросы к базе
  - job_name: 'postgres'
    scrape_interval: 120s
    scrape_timeout: 60s
    static_configs:
      - targets: ['pg-exporter:9187']
 
  # Сертификаты живут месяцами, но выше 5 минут поднимать нельзя — почему, ниже
  - job_name: 'blackbox-ssl'
    scrape_interval: 300s
    scrape_timeout: 30s
    static_configs:
      - targets: ['blackbox:9115']

Ориентиры, от которых удобно отталкиваться:

Что измеряемИнтервалПочему так
Время ответа, RPS, ошибки HTTP10–30 соснова алертов, нужна быстрая реакция
CPU, память, сеть хоста30–60 свсплески заметны и на минутной сетке
Heap, GC, event loop lag15–30 сдеградация развивается за секунды
Тяжёлые экспортеры БД60–120 скаждый скрейп нагружает саму базу
Место на диске, inode60–300 сзаполняется часами и днями
Срок сертификатов, домены300 сменяется раз в месяцы

Проверить себя помогает один вопрос: что я сделаю, если увижу изменение этой метрики через 5 секунд, а не через минуту? Если ответ «ничего, я всё равно смотрю на неё в отчёте раз в неделю» — частый опрос здесь не нужен.

Границы, которые задаёт сам Prometheus

Три ограничения, о которые чаще всего спотыкаются при настройке интервалов.

Интервал больше 5 минут ломает графики. В PromQL значение считается актуальным ограниченное время — по умолчанию 5 минут (--query.lookback-delta). Если опрашивать реже, между точками появятся разрывы: график рвётся, а выражения вроде up == 0 начинают вести себя непредсказуемо. Практический вывод: 5 минут — верхняя граница разумного интервала, даже для метрик, которые меняются раз в месяц.

Окно в rate() должно быть минимум вчетверо больше интервала. Чтобы посчитать скорость, нужно хотя бы две точки в окне, а с запасом на пропущенный скрейп — четыре. При scrape_interval: 60s выражение rate(http_requests_total[1m]) будет то работать, то давать пустоту:

# плохо: окно равно интервалу опроса
rate(http_requests_total[1m])

# хорошо: окно с запасом на пропущенные скрейпы
rate(http_requests_total[5m])

Отсюда важное следствие: меняя интервал опроса, нужно пересматривать и окна во всех запросах и алертах. Увеличили интервал с 15 до 60 секунд — часть дашбордов молча опустеет.

scrape_timeout не может быть больше scrape_interval. Prometheus не запустится с такой конфигурацией. И если у джоба таймаут почти равен интервалу, следующий опрос начнётся сразу после предыдущего — экспортёр окажется под непрерывной нагрузкой.

Не забывайте про нагрузку на экспортёры

Большинство экспортёров дешёвые, но некоторые при каждом запросе делают реальную работу: обходят таблицы в базе, опрашивают JVM, собирают статистику по контейнерам или ходят по SNMP до сетевого железа. Для них частый опрос — это нагрузка на прод, а не на мониторинг.

Кто именно отвечает медленно, видно из служебных метрик:

topk(10, scrape_duration_seconds)
topk(10, scrape_samples_scraped)

Правило простое: если scrape_duration_seconds у джоба стабильно превышает половину его scrape_interval, интервал для этого экспортёра уже слишком мал. Дальше начинаются таймауты, а таймаут выглядит в мониторинге как up == 0 — то есть как ложная авария. Подробнее про сами экспортёры и их метрики — в статье о том, как расширять метрики Prometheus.

Интервал напрямую задаёт скорость обнаружения

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

scrape_interval + for + evaluation_interval + group_wait

Посчитаем на конкретных значениях: опрос раз в 30 секунд, условие for: 90s (три проверки подряд), правила вычисляются раз в 30 секунд, group_wait в Alertmanager стоит по умолчанию 30 секунд. В худшем случае получается три минуты — а не полторы, как кажется по одному лишь for.

Именно поэтому «уменьшить интервал» редко бывает правильным первым шагом. Если нужно ускорить реакцию, сначала посмотрите на остальные три слагаемых: часто там лежат минуты, которые дешевле сократить. И наоборот — если алерты шумят, увеличенный for обойдётся дешевле, чем более частый опрос. Подробнее об этом — в статьях про алерты, которые не раздражают и burn rate alerts.

Что делать вместо уменьшения интервала

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

Выбросить ненужные метрики на приёме. Экспортёры отдают куда больше, чем вам нужно. Лишнее отсекается на этапе сбора:

    metric_relabel_configs:
      # Гистограммы по каждому пути дают тысячи серий на один сервис
      - source_labels: [__name__]
        regex: 'go_gc_duration_seconds.*'
        action: drop

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

groups:
  - name: api
    interval: 30s
    rules:
      - record: job:http_request_errors:rate5m
        expr: sum by (job) (rate(http_requests_total{code=~"5.."}[5m]))

Найти, кто именно съедает кардинальность. Чаще всего это одна-две метрики с идентификатором в лейбле — user id, путь с параметрами, trace id:

topk(10, count by (__name__) ({__name__=~".+"}))

Запрос тяжёлый, на большой базе его лучше выполнять не в разгар инцидента. Зато результат обычно объясняет рост хранилища лучше любых расчётов.

Пересматривайте настройки по мере роста

Интервалы, подобранные для десяти серверов, на сотне могут оказаться неподъёмными: количество серий растёт вместе с инфраструктурой, а стоимость — по произведению. Раз в несколько месяцев полезно свериться:

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

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

Что почитать дальше

Заключение

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

Дальше держите в голове три числа: сколько сэмплов в секунду вы принимаете, сколько это занимает на диске за срок хранения и через сколько секунд после сбоя приходит уведомление. Если хочется ускорить реакцию — сначала посмотрите на for, evaluation_interval и group_wait, а если мониторингу тяжело — на количество серий. Интервал стоит менять последним: он влияет не только на нагрузку, но и на все окна в запросах и алертах, которые придётся пересматривать вместе с ним.

Опубликовано 27 июля 202610 минут чтенияАнастасия Левина
Средний рейтинг статьи — 4.8

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний