VictoriaMetrics, разделяй и агрегируй! Оптимизация хранения метрик

от автора

Доброго, товарищи инженеры!
Меня зовут Алексей Зернов. В этом материале речь пойдёт о разделении метрик в VictoriaMetrics на два независимых потока. Статья не предполагает глубокого погружения в базовые сущности VictoriaMetrics и холивары по использованию того или иного инструмента для работы с метриками – в конце концов, инструмент остаётся всего лишь инструментом.

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

Простое агрегирование всех метрик не является оптимальным решением, так как приводит к потере детализации для оперативного мониторинга. В то же время хранение сырых данных увеличивает объём storage до 3 ТБ.

Не то чтобы было сильно жалко дискового пространства, но зачем?

Multi Retention подходит для этой задачи, но работает только на VictoriaMetrics Enterprise. Поскольку мы используем open-source версию, нам потребовалось альтернативное решение — разделение метрик между разными хранилищами.

Решение выглядит так:

  • В первом хранилище метрики будут доступны 30 дней в первозданном виде, без изменений. Хранилище сырых метрик для наблюдаемости, мониторинга и реагирования на инциденты в моменте.

  • Второе хранилище на 180 дней, и метрики там будут доступны в агрегированном за 5 минут виде.

Введение

Прежде чем начать, стоит немного разобраться, с чем нам предстоит столкнуться. Как уже было сказано ранее, «статья не предполагает глубокого погружения в базовые сущности», поэтому описание будет кратким. Итак:

Использованные компоненты VictoriaMetrics

  • vmagent – Агент для сбора метрик. Может копать, может не копать.

  • vminsert – На нём приём и запись метрик в vmstorage.

  • vmstorage – Отвечает за хранение метрик.

  • vmselect – Выполняет запросы метрик из vmstorage.

Основная работа будет выполнена с этими сущностями, поэтому vmalert, vmauth, alertmanager и т.д. не описываем.

Целевая схема

Целевая схема решения выглядит вот так:

Схема 1

Схема 1

Чтобы удобнее описывать добавим на схему точки:

Схема 2

Схема 2

Описание целевой схемы

  1. Vmaget в кластере k8s-cluster number-two собирает метрики с этого кластера и отправляет их VMAgent_gateway(4).

  2. Node Exporters развёрнуты на серверах, виртуальных машинах и собирают с них метрики. Эти метрики забирает VMAgent_Gateway(4).

  3. Метрики кластера, собранные через victoria-kube-state-metrics. Эти метрики также забирает VMAgent_Gateway(4).

  4. VMagent_gateway. Забирает метрики со всех сущностей, которые есть в scrape конфигах, также принимает метрики от других агентов. Агент именно из victoria-metrics-k8s-stack выбран как gateway, потому что при развёртывании оператора, сущности оператора автоматически собирают метрики кластера, а также все таргеты в скрейпах по дефолту обрабатывает именно этот агент. VMagent_gateway через remoteWrite пушит все метрики в VMAgent_raw(6).

  5. RAW-Cluster.  Кластер для хранения сырых (необработанных) метрик. Компоненты:

    • VMinsert_raw: Вставляет сырые метрики полученные от VMAgent_raw(6) в хранилище.

    • VMStorage_raw: Хранилище сырых метрик.

    • VMSelect_raw: Позволяет выполнять запросы сырых метрик, хранящихся в VMStorage_raw

  6. VMAgent_raw. Получает сырые метрики от VMAgent_gateway и через remoteWrite пушит их в VMInsert_raw и VMAgent_aggr. На VMAgent_raw полностью отключены все скрейпы.

  7. VMAgent_aggr.  Получает сырые метрики от VMAgent_raw, агрегирует и отправляет дальше в VMInsert_aggr. Скрейпы полностью отключены.

  8. AGGR-Cluster. Кластер для хранения агрегированных метрик.  Компоненты:

    • VMIsert_aggr: Получает агрегированные метрики от VMAgent_aggr и отправляет в хранилище. — VMStorage_aggr: Хранилище агрегированных метрик.

    • VMSelect_aggr: Позволяет выполнять запросы агрегированных метрик, хранящимся в VMStorage_aggr.

  9. Grafana. Подключается к VMSelect_raw и VMSelect_aggr для выполнения запросов и получения данных для визуализации.

Если подвести итог, то мы получили следующие ключевые особенности архитектуры:

  • Разделение потоков данных (сырые/агрегированные).

  • Многоуровневая обработка метрик.

  • Централизованный сбор через gateway-узел.

  • Гибкость запросов через отдельные точки доступа.

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

Расчёт объёмов vmstorage

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

  • На сегодня обёем текущего vmstorage – 3ТБ.

  • Храним сырые метрики 180 дней. Рассчитываем необходимый объём на сырые метрики 30 дней.

Сырые:

  • Берём 1/6 от 3 ТБ → 512 ГБ (месяц 1/6 от полугода).

  • Запас на отказоустойчивость (чтобы, если одна нода упадёт, всё не сгорело).

  • Формула: ((объём / кол-во нод) * (кол-во нод / 2)) + объём.

  • (6 нод): ((512 / 6) * 3) + 512 ≈ 768 ГБ.

  • Запас на рост (30%) (потому что метрики имеют привычку неожиданно расти).

  • 512 + 30% ≈ 666 ГБ.

Агрегированные:

  • Сжатие в ~20 раз (300s / 15s) → 153 ГБ.

  • Объясню подробнее: у нас исходные метрики приходят каждые 15 секунд (стандартный scrape_interval), мы их агрегируем в 5-минутные интервалы (300 секунд).

  • 300s / 15s = 20 (столько исходных точек «упаковываем» в одну агрегированную).

  • Отсюда и получаем примерное 20-кратное сжатие по объёму. Но это в теории, на самом деле значение усреднённое. Но, принимая его за константу, получаем:

  • 3ТБ сырых → 3 ТБ / 20 ≈ 0.15 ТБ (153 ГБ) агрегированных.

  • Запас на отказоустойчивость**:**

  • (6 нод):((153 / 6) * 3) + 153 ≈ 230 ГБ

  • Запас на рост (30%)

  • 230 + 30% ≈ 299 ГБ

Итого:
RAW-кластер: 700-800 ГБ
AGGR-кластер: 250-300 ГБ

В общем, на основе этих расчётов был использован 1ТБ на сырые, 1ТБ на агрегированные. М-математика.

Использованные Helm-чарты

Для решения задачи было принято решение использовать вот такие чарты:

Про развёртывание

Для развёртывания чартов используется ArgoCD, но углубляться в него здесь нет необходимости. Краткой схемы, которая используется для развертывания, достаточно для контекста.

  • victoria-metrics(victoria-metrics-k8s-stack-0.36.0) – основной стек для сбора, хранения метрик. В нем же vmagent-gateway.

  • victoria-configs(Manifests) – конфиги для victoria-metrics(victoria-metrics-k8s-stack-0.36.0), (scrape, rules, recording rules).

  • victoria-secrets(Manifests) – секреты (SMTP, webhook, API-ключи и т. д.)

  • victoria-aggr(victoria-metrics-cluster) – хранение агрегированных метрик.

  • victoria-aggr-agent(victoria-metrics-agent) – агент, который принимает, агрегирует и отправляет в vminsert уже агрегированные метрики.

  • victoria-raw-agent(victoria-metrics-agent) – агент, который принимает от vmagent-gateway метрики и отправляет их в vminsert-raw и vmagent-aggr.

  • victoria-agent(victoria-metrics-agent) – на кластере k8s-cluster number-two.

Values для всего

Итак, с теоретической частью закончили, можно переходить к values файлам. Опять же, не хочется превращать короткую статью в посимвольное описание типовых values, поэтому добавим только то, что действительно нужно.
Дедупликация, репликация, шардирование, количество метрик в очереди и иже с ними – это тоже не тема статьи, а личный выбор каждого. Поэтому по ним только поверхностно.
С первого values.

Victoria-metrics(victoria-metrics-k8s-stack-0.36.0)

# Секция vmcluster vmcluster:   enabled: true  # Включаем установку кластера VictoriaMetrics   annotations: {}   spec:     retentionPeriod: "30d"  # Храним данные 30 дней     replicationFactor: 1  # Репликация данных отключена (1 = без репликации)     # Отказоустойчивость отдана на откуп цефу, с нас шаридирование.       # Настройки vmstorage     vmstorage:       image:         repository: artifactory.com/vmstorage         tag: v1.110.0-cluster       replicaCount: 6  # 6 реплик vmstorage для шардирования(6 шардов, быстро, модно)       storageDataPath: /vm-data  # Путь для данных внутри контейнера       storage:         volumeClaimTemplate:           spec:             resources:               requests:                 storage: 165Gi  # По 165GB на каждый pod (6*165GB = ~1TB общего хранилища)             storageClassName: metrics-csi-sc  # Используем Ceph RBD             volumeMode: Filesystem       resources:         limits:           cpu: "12"           memory: "80Gi"         requests:           cpu: "3"           memory: "30Gi"       extraArgs:         search.maxUniqueTimeseries: "1000000"  # Лимит уникальных временных рядов       # Настройки vmselect     vmselect:       image:         repository: artifactory.com/vmselect         tag: v1.110.0-cluster       port: "8481"       replicaCount: 4  # 4 реплики для одновременной обработки запросов       cacheMountPath: /select-cache  # Путь для кеша       extraArgs:         search.maxConcurrentRequests: "100"  # Увеличено с дефолтных 16. Ограничивает максимальное количество запросов, которые vmselect может обрабатывать одновременно.         search.maxQueryDuration: 120s  # Увеличено с 60s. Максимальное время выполнения одного запроса. Если запрос выполняется дольше — он принудительно завершается с ошибкой.         search.maxQueryLen: "510000"  # Лимит длины запроса. Ограничивает длину запроса в байтах (например, длинный PromQL или URL с фильтрами). Дефолтный 16КБ, у нас 500КБ         search.maxSeries: "1000000"  # Макс кол-во series в ответе. Максимальное количество time series, которые могут быть возвращены в одном ответе.         search.maxUniqueTimeseries: "900000"  # Увеличено с 300k. Ограничивает количество уникальных рядов, которые vmselect будет обрабатывать в течение 5 минут (кэш запросов).         search.maxQueueDuration: "5m"  # Макс время в очереди. Максимальное время, которое запрос может ждать в очереди, если все слоты (maxConcurrentRequests) заняты.         search.logSlowQueryDuration: 180s  # Логирование медленных запросов >180s. Логирует медленные запросы (duration > 180s) в деталях.       storage:         volumeClaimTemplate:           spec:             resources:               requests:                 storage: 5Gi  # 5GB на кеш для каждого vmselect             storageClassName: metrics-csi-sc             volumeMode: Filesystem       resources:         limits:           cpu: "2"           memory: "8Gi"         requests:           cpu: "1"           memory: "4Gi"       # Настройки vminsert     vminsert:       image:         repository: artifactory.com/vminsert         tag: v1.110.0-cluster       port: "8480"       replicaCount: 2  # 2 реплики для входящего трафика       resources:         limits:           cpu: "4"           memory: 4Gi         requests:           cpu: "2"           memory: "2Gi"       extraArgs:         insert.maxQueueDuration: 5m0s  # Макс время в очереди на вставку         maxConcurrentInserts: "128"  # Макс параллельных вставок         maxLabelsPerTimeseries: "36"  # Лимит лейблов на временной ряд      # Секция vmagent (4) на схеме 2, он же gateway   vmagent:   enabled: true   spec:     selectAllByDefault: true     scrapeInterval: 25s     # -- Глобальные метки, добавляемые ко всем метрикам     externalLabels:       source_metrics: k8s-cluster-number-one  # Идентификатор кластера     # -- Основные эндпоинты для отправки метрик (remote-write)     remoteWrite:       # -- Отправка на raw agent точка (6) на схеме 2       - url: "http://victoria-raw-agent-victoria-metrics-agent.victoriametrics:8429/api/v1/write"     extraArgs:       promscrape.streamParse: "true" # -- Парсить метрики в потоковом режиме (экономит память)       promscrape.dropOriginalLabels: "true" # -- Удалять оригинальные labels после обработки       promscrape.maxScrapeSize: "671088640" # -- Максимальный размер одного scrape (64MB)       remoteWrite.queues: "10" # -- Количество очередей для отправки метрик   

Этого достаточно для первичной настройки, node-exporters, kube-state-metrics и т.д. включены, но не обсуждаем.

Victoria-aggr(victoria-metrics-cluster)

Просто включили кластерные компоненты (vminsert, vmselect, vmstorage), настроили ресурсы, добавили период хранения для vmstorage, и всё на этом, остальное не нужно.

vmselect:   enabled: true vminsert:   enabled: true vmstorage:   enabled: true   retentionPeriod: "180d" 

Victoria-aggr-agent(victoria-metrics-agent)

Здесь добавили remoteWrite до Victoria-aggr(victoria-metrics-cluster) (8), схема 2, конфигурацию агрегации (все метрики за 5 минут), а также отключили скрейп.

remoteWrite: - url: "http://victoria-aggr-victoria-metrics-cluster-vminsert.victoriametrics:8480/insert/0/prometheus/api/v1/write"   extraArgs:   envflag.enable: true   envflag.prefix: VM_   loggerFormat: json   httpListenAddr: :8429   remoteWrite.streamAggr.config: /etc/vmagent/extra/remotewrite_streamAggr_config.yml   promscrape.config: /etc/vmagent/extra/promscrape_config.yml   remoteWrite.streamAggr.keepInput: "false"   streamAggr.dedupInterval: "5m" # Дедупликация перед агрегацией   remoteWrite.streamAggr.dedupInterval: "5m"   # -- Extra Volumes for the pod extraVolumes: - name: config-volume   configMap:     name: victoriametrics-agent-streamaggr-config   # -- Extra Volume Mounts for the container extraVolumeMounts: - name: config-volume   mountPath: /etc/vmagent/extra   extraObjects: - apiVersion: v1   kind: ConfigMap   metadata:     name: victoriametrics-agent-streamaggr-config   data:     remotewrite_streamAggr_config.yml: |       - match: '{__name__=~".+"}'         interval: 5m         outputs: [count_samples, sum_samples, min, max, avg]     promscrape_config.yml: |       global:         scrape_interval: 5m       scrape_configs: []  

Victoria-raw-agent(victoria-metrics-agent)

Здесь мы добавляем два remoteWrite в соответствии со схемой, точки 6 — > 5, 6 -> 7.  А также отключаем скрейп этим агентом.

remoteWrite: - url: "http://victoria-aggr-agent-victoria-metrics-agent.victoriametrics:8429/api/v1/write" # в след. агент на агрегацию - url: "http://vminsert-victoria-victoria-metrics-k8s-stack.victoriametrics:8480/insert/0/prometheus/api/v1/write" # сырые метрики   extraObjects: - apiVersion: v1 # Для отключения используем конфигмап с пустым скрейпом.   kind: ConfigMap   metadata:     name: victoriametrics-agent-promscrape-config-raw   data:     promscrape_config.yml: |       global:         scrape_interval: 15s       scrape_configs: []   # -- VMAgent extra command line arguments extraArgs:   envflag.enable: true   envflag.prefix: VM_   loggerFormat: json   httpListenAddr: :8429   promscrape.config: /etc/vmagent/extra/promscrape_config.yml   promscrape.dropOriginalLabels: "true" 

Victoria-agent(victoria-metrics-agent)

В этом values нам достаточно указать агенту, куда отправлять метрики кластера и добавить ему лейбл.

vmagent: enabled: true spec:   image:     repository: artifactory.com/vmagent   selectAllByDefault: true   scrapeInterval: 20s   externalLabels:     source_metrics: k8s-cluster-number-two   extraArgs:     promscrape.streamParse: "true"     promscrape.dropOriginalLabels: "true"     remoteWrite.queues: "10"     remoteWrite.url: "https://vmagent-gateway.com/api/v1/write" 

Картинки результата.

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

Рис.1

Рис.1

И так выглядят сырые метрики:

Рис.2

Рис.2

Все вышло так, как и планировалось. Но если смотреть в Grafana, то могут возникнуть сомнения, ведь точки на дашборде с агрегированными метриками есть не только на 5 минутах, а также на промежутках, вот так:

Рис.3

Рис.3

Поэтому проверим через vmui c raw-query, чтобы убедиться наверняка:

Рис.4

Рис.4

Вот теперь точно всё по плану.

Вывод.

Наше решение с разделением метрик на сырые (30 дней) и агрегированные (180 дней) потоки доказало свою жизнеспособность, но, как и любая архитектура, имеет свои сильные и слабые стороны.

Теперь преимущества:

  • Экономия ресурсов. Сокращение объёма хранилища с 3ТБ до 2ТБ без потери критичных данных.

  • Сохранение гибкости.

  • Сырые метрики доступны для детального анализа инцидентов, т.е. мониторинг и наблюдаемость в моменте никуда не делись.

  • Агрегированные данные позволяют строить долгосрочные тренды без «раздувания» по объёму.

  • Масштабируемость. Каждый компонент (RAW/AGGR) можно масштабировать независимо.

  • Реализовали аналог Multi Retention без VictoriaMetrics Enterprise.

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

Ну и минусы, соответственно:

  • Усложнение инфраструктуры.

  • Дополнительные компоненты (vmagent-raw, vmagent-aggr) требуют мониторинга и поддержки.

  • Риск «разрыва» цепочки передачи данных между агентами.

  • Потеря детализации в долгосрочных данных. Агрегация 5-минутных интервалов может скрыть аномалии, длящиеся 1–2 минуты. Но это минус больше перестраховка, у нас же есть сырые метрики.

  • Два разных источника. Неудобство. Но, как и писал выше, это – как минус, так и плюс.

Итог.

Решение подходит для нашей задачи, где оперативный мониторинг важнее долгосрочной детализации, но долгосрочное хранение быть должно. Главное — баланс между:

  • экономией (2 ТБ вместо 3 ТБ)

  • гибкостью (сырые + агрегированные данные),

  • производительностью (разделение нагрузки).

Однако за это приходится платить усложнением инфраструктуры. Но, к этому мы были готовы на этапе планирования.

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


ссылка на оригинал статьи https://habr.com/ru/articles/922168/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *