Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

Prometheus: cardinality, relabeling и downsampling — как держать TSDB под контролем

High cardinality в Prometheus незаметно раздувает TSDB, замедляет запросы и усложняет compaction. Разбираем, откуда берутся миллионы рядов, как резать поток metric_relabel_configs, что ожидать от remote_write и где уместен downsampling.
Prometheus: cardinality, relabeling и downsampling — как держать TSDB под контролем

Почему Prometheus «раздувается» и чем опасна высокая кардинальность

Prometheus хранит данные как набор временных рядов (time series). Каждый ряд однозначно определяется именем метрики и полным набором лейблов. Появилось новое уникальное сочетание лейблов — появился новый ряд, и он начинает жить в TSDB, занимая память под индекс (head), дисковое место под чанки и ресурсы на компакцию.

High cardinality — это ситуация, когда число уникальных рядов становится очень большим (десятки/сотни тысяч и выше на один Prometheus, иногда миллионы). Обычно это проявляется ростом tsdb size, увеличением задержек запросов, удлинением компакций, а на пиках — упором в OOM или деградацией из‑за давления на память/GC.

«Плохая» кардинальность — не абсолютное число, а сочетание скорости появления новых серий, объёма данных и лимитов сервера. 300k серий на мощном узле могут быть нормой, а 300k на маленьком сервере — уже проблема. Почти всегда первопричина одна: лишние лейблы, плодящие уникальные комбинации.

Три источника проблем: метрики, лейблы, динамика

  • Метрики с потенциально бесконечным набором значений: request_id, user_id, session, query, path с параметрами, stacktrace и т.д.
  • Лейблы с высокой вариативностью: pod UID, container_id, instance с ephemeral портом, hostname на автоскейле, image digest.
  • Частая смена целей: короткоживущие pods/jobs, которые постоянно создают новые instance/pod/endpoint.

Кардинальность — это не только «сколько рядов сейчас», но и «как быстро появляются новые». Быстрое создание/удаление pod’ов может накручивать серии даже при умеренном текущем количестве целей.

Как быстро диагностировать high cardinality в Prometheus

Первый шаг — понять, что именно раздувает TSDB: конкретные метрики, конкретные лейблы или конкретные джобы. Чем быстрее вы найдёте «виновника», тем меньше будет соблазн лечить симптомы (retention/железо) вместо причины.

Базовые метрики Prometheus про себя

Эти метрики помогают понять, насколько TSDB «тяжёлая» прямо сейчас:

  • prometheus_tsdb_head_series — сколько серий сейчас в head (горячей части).
  • prometheus_tsdb_head_chunks — число чанков в head.
  • prometheus_tsdb_head_samples_appended_total — скорость записи (косвенно влияет на I/O и compaction).
  • prometheus_tsdb_compactions_total и длительности компакций — если времена растут, TSDB становится тяжелее обслуживать.

PromQL-запросы, чтобы найти виновников

Ниже — типовые запросы, которые помогают локализовать проблему. Если Prometheus уже «задыхается», начинайте с ограничения по job/namespace и избегайте запросов «по всему миру».

Топ метрик по числу серий:

topk(20, count by (__name__) ({__name__!=""}))

Топ джобов по числу серий (часто быстро показывает источник взрыва):

topk(20, count by (job) ({__name__!=""}))

Проверка конкретного лейбла на «взрыв» значений (пример для path):

topk(20, count by (path) ({job="api"}))

Сколько уникальных значений у лейбла (грубая оценка на примере pod):

count(count by (pod) ({job="kube-state-metrics"}))

Если такие запросы слишком дорогие, используйте TSDB status-страницу (в новых версиях Prometheus она хорошо помогает увидеть «тяжёлые» лейблы и метрики) или снимайте данные по частям: по одному job, по одному namespace, по одному экспортеру.

Для алертов, связанных с доступностью сервисов (а не с внутренней кардинальностью), часто полезно держать отдельный лёгкий мониторинг с blackbox‑проверками. В этом контексте пригодится материал про Prometheus Blackbox Exporter для HTTP/TCP/ICMP проверок.

Диагностика кардинальности: метрики Prometheus и поиск самых «тяжёлых» рядов

Relabeling: где резать — в target relabeling или metric relabeling

В Prometheus есть два разных этапа relabeling, и их важно не путать:

  • relabel_configs — работает до скрейпа, на уровне целей (targets). Здесь вы фильтруете/переписываете цели, собираете адрес, правите job/instance, отсеиваете лишние endpoints.
  • metric_relabel_configs — работает после скрейпа, на уровне каждой метрики. Именно здесь обычно лечат кардинальность: дропают метрики, выкидывают лейблы, нормализуют значения.

Если вы боретесь с high cardinality, чаще всего вам нужен metric_relabel_configs: он не даёт метрикам попасть в TSDB. relabel_configs полезен, когда проблема в лишних таргетах или в неправильной разметке job/instance.

Приём №1: выкинуть «мусорные» метрики на входе

Классический вариант — отбрасывать метрики по имени или по лейблам, если вы точно понимаете, что они вам не нужны. Пример ниже показывает «жёсткий» режим: оставить только одну метрику (остальное отрезать).

scrape_configs:
  - job_name: "api"
    static_configs:
      - targets: ["10.0.0.10:9100"]
    metric_relabel_configs:
      - source_labels: [__name__]
        regex: "http_server_requests_seconds_bucket"
        action: keep

Более мягко — точечно дропать самые тяжёлые метрики:

metric_relabel_configs:
  - source_labels: [__name__]
    regex: "(http_server_requests_seconds_bucket|http_request_duration_seconds_bucket)"
    action: drop

Перед тем как дропать гистограммы, проверьте, не убьёте ли вы SLO/latency‑аналитику. Часто лучше уменьшить число bucket’ов на стороне приложения (это уменьшает число серий в разы), чем полностью выкинуть метрику.

Приём №2: labeldrop и labelkeep — когда метрика полезна, но лейблы слишком «жирные»

Если метрика нужна, но у неё есть лейблы с высокой вариативностью, обычно помогает выбросить конкретные метки или зафиксировать «белый список» разрешённых.

Пример: убираем лейбл request_id, который делает серию уникальной для каждого запроса:

metric_relabel_configs:
  - regex: "request_id"
    action: labeldrop

Вариант с политикой «разрешены только эти метки»:

metric_relabel_configs:
  - regex: "(__name__|job|instance|method|status|le)"
    action: labelkeep

labelkeep хорош тем, что фиксирует контракт: «в TSDB допускаем только такой набор измерений». Но будьте внимательны: можно случайно выкинуть важный разрез (например, namespace или pod) и затем получить слишком агрегированные графики.

Приём №3: нормализация лейбла через replace (аккуратно)

Иногда лейбл нужен, но его значения надо «укрупнить». Типичный пример — path, где есть идентификаторы: /users/12345, /users/67890. В идеале это делается в приложении (отдавать template route), но частично можно помочь relabel’ом.

metric_relabel_configs:
  - source_labels: [path]
    regex: "(.*)/[0-9]+(.*)"
    target_label: path
    replacement: "$1/:id$2"
    action: replace

Учтите два ограничения: regex‑замены на потоке метрик добавляют CPU, а «универсальная» регулярка легко ломает полезную детализацию. Делайте это только при понятной структуре путей и измеримом эффекте.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Retention и tsdb size: как связаны кардинальность, частота скрейпа и срок хранения

Размер TSDB определяется в основном тремя параметрами: сколько серий, как часто вы скрейпите и сколько дней храните. Упрощённо:

  • Больше серий → больше индекса и чанков.
  • Меньше scrape_interval (например, 5s вместо 30s) → больше сэмплов → выше I/O и больше данных на диске.
  • Больше retention → больше блоков на диске и дольше компакции при тех же объёмах.

Если лечить только retention, но не убирать high cardinality, вы лишь отложите проблему. Prometheus всё равно будет тяжёлым в runtime: head/индекс/compaction будут страдать даже при коротком хранении.

Практичный порядок действий обычно такой:

  1. Снизить кардинальность: drop/labeldrop/уменьшить buckets, убрать динамические лейблы.
  2. Подобрать scrape_interval и retention под задачи (разные интервалы для разных job — это нормально).
  3. И только затем думать про downsampling и/или вынос истории через remote_write.

Если Prometheus стоит на небольшом сервере, кардинальность особенно быстро упирается в RAM и IOPS. В таких случаях имеет смысл либо правильно «подрезать» метрики, либо переносить сборщик на более ресурсный узел, например на VDS с предсказуемыми лимитами по памяти и диску.

Remote write: как вынос метрик помогает (и почему он не лечит кардинальность сам по себе)

remote_write часто воспринимают как «спасение от раздувания TSDB». Частично это так: можно держать на локальном Prometheus небольшой retention (например, 6–24 часа) для оперативных алертов, а долгую историю отправлять в удалённое хранилище.

Но нюанс важный: remote_write не уменьшает кардинальность автоматически. Если вы продолжаете ingest’ить миллионы рядов локально, Prometheus всё равно платит цену за head/индекс, даже если хранит данные недолго. Поэтому remote_write — это про архитектуру и long‑term storage, а не про «волшебное сжатие».

Практичный паттерн: короткий локальный retention + внешний long-term storage

Схема обычно такая:

  • Prometheus: ingestion + rules/alerts + короткая история.
  • Удалённое хранилище: длительная история, отчёты, запросы по месяцам.

Что обязательно контролировать в эксплуатации:

  • Очередь remote write: если удалённое хранилище тормозит, растёт буфер и потребление памяти.
  • Фильтрация до отправки: иногда разумно отправлять только «сигнальные» метрики (SLO, инфраструктура), а «шум» отбрасывать ещё до TSDB.
  • Разделение потоков: разные remote_write для разных наборов метрик упрощают управление стоимостью и отказами.

Схема: Prometheus с коротким retention и отправка метрик через remote_write во внешнее хранилище

Downsampling: когда нужен и где его делать правильно

Downsampling — это уменьшение детализации данных для долгого хранения: например, точные данные за последние 2 дня, а дальше — 1 точку в минуту/5 минут/час. Это экономит место и ускоряет запросы по большим диапазонам.

Ключевой момент: классический Prometheus не делает downsampling «из коробки» для собственного TSDB. Если вы хотите downsampling, обычно это делается в long‑term storage или через запись агрегатов отдельными рядами.

Практика №1: записывать агрегаты как отдельные метрики (recording rules)

Самый контролируемый способ — заранее создавать «сжатые» ряды через recording rules и хранить их дольше, чем «сырьё». Пример: вместо хранения per‑instance метрик годами — хранить агрегаты по сервисам.

groups:
  - name: downsample_rules
    interval: 1m
    rules:
      - record: job:http_requests_total:rate1m
        expr: sum by (job, method, status) (rate(http_requests_total[1m]))

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

Практика №2: downsampling на стороне remote-хранилища

Если long‑term storage умеет хранить несколько уровней детализации или эффективно агрегировать, логичнее оставить Prometheus «оперативным сборщиком», а downsampling вынести наружу. Это снижает количество логики в rules и уменьшает риск «не туда агрегировать», но зависит от выбранного стека и требований к запросам.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Чек-лист: как снижать кардинальность без потери наблюдаемости

Ниже — последовательность, которая обычно даёт максимум эффекта при минимуме сюрпризов.

1) Зафиксируйте базовую точку и цели

  • Снимите текущие значения prometheus_tsdb_head_series и размер диска под TSDB.
  • Составьте список критичных дашбордов/алертов: latency, error rate, saturation (CPU/RAM/disk), внешняя доступность.

2) Найдите топ-метрики по числу серий

  • Если «виноваты» гистограммы — начните с уменьшения количества bucket’ов на стороне приложения.
  • Если «виноваты» лейблы типа path/query/user — почти всегда нужен drop/labeldrop.

3) Внедрите metric_relabel_configs как «отсечку»

  • Точечные drop для самых дорогих метрик.
  • labelkeep как политика для разрешённых лейблов (контракт на измерения).
  • Минимизируйте regex‑магию; если можно — исправьте экспортер/приложение.

4) Настройте retention осознанно

  • Оперативные разборы инцидентов обычно укладываются в часы/дни, не месяцы.
  • Долгая история нужна для трендов — там чаще выигрывают агрегаты и downsampling.

5) Подключайте remote_write как следующий шаг

  • Выносите долгую историю, но не оставляйте high cardinality «как есть».
  • Следите за стабильностью канала и метриками очередей remote write.

Типовые анти-паттерны (и чем заменить)

  • Лейбл с уникальным значением на каждый запрос → оставьте в метриках статус/метод/handler, а детализацию унесите в логи или трассировку.
  • Хранить всё «на всякий случай» → «сырьё» храните кратко, тренды — агрегатами.
  • Пытаться лечить только retention → сначала снижайте кардинальность, иначе head и индекс всё равно будут тяжёлыми.
  • Один и тот же маленький scrape_interval для всего → сделайте разные интервалы по джобам: критичное 10–15s, остальное 30–60s.

Мини-итог

Борьба с high cardinality в Prometheus — это дисциплина по лейблам и метрикам. Правильно применённые metric_relabel_configs обычно дают самый быстрый эффект: меньше серий → меньше TSDB → проще удерживать нужный retention и стабильную скорость запросов. remote_write и downsampling — следующий уровень: про архитектуру хранения и стоимость долгой истории, но они не заменяют гигиену кардинальности.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...