Как стать автором
Обновить
94.84

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

Уровень сложностиСредний
Время на прочтение10 мин
Количество просмотров416

Доброго, товарищи инженеры!
Меня зовут Алексей Зернов. В этом материале речь пойдёт о разделении метрик в 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 ТБ)

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

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

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

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

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+3
Комментарии0

Публикации

Информация

Сайт
t2.ru
Дата регистрации
Дата основания
Численность
5 001–10 000 человек
Местоположение
Россия