Доброго, товарищи инженеры!
Меня зовут Алексей Зернов. В этом материале речь пойдёт о разделении метрик в VictoriaMetrics на два независимых потока. Статья не предполагает глубокого погружения в базовые сущности VictoriaMetrics и холивары по использованию того или иного инструмента для работы с метриками – в конце концов, инструмент остаётся всего лишь инструментом.
Проблема, которую мы решаем, формулируется следующим образом: на текущий момент нам необходимо хранить метрики за 180 дней, что создаёт сложности как с хранением данных, так и с обработкой запросов к ним.
Простое агрегирование всех метрик не является оптимальным решением, так как приводит к потере детализации для оперативного мониторинга. В то же время хранение сырых данных увеличивает объём storage до 3 ТБ.
Не то чтобы было сильно жалко дискового пространства, но зачем?
Multi Retention подходит для этой задачи, но работает только на VictoriaMetrics Enterprise. Поскольку мы используем open-source версию, нам потребовалось альтернативное решение — разделение метрик между разными хранилищами.
Решение выглядит так:
-
В первом хранилище метрики будут доступны 30 дней в первозданном виде, без изменений. Хранилище сырых метрик для наблюдаемости, мониторинга и реагирования на инциденты в моменте.
-
Второе хранилище на 180 дней, и метрики там будут доступны в агрегированном за 5 минут виде.
Введение
Прежде чем начать, стоит немного разобраться, с чем нам предстоит столкнуться. Как уже было сказано ранее, «статья не предполагает глубокого погружения в базовые сущности», поэтому описание будет кратким. Итак:
Использованные компоненты VictoriaMetrics
-
vmagent – Агент для сбора метрик. Может копать, может не копать.
-
vminsert – На нём приём и запись метрик в vmstorage.
-
vmstorage – Отвечает за хранение метрик.
-
vmselect – Выполняет запросы метрик из vmstorage.
Основная работа будет выполнена с этими сущностями, поэтому vmalert, vmauth, alertmanager и т.д. не описываем.
Целевая схема
Целевая схема решения выглядит вот так:
Чтобы удобнее описывать добавим на схему точки:
Описание целевой схемы
-
Vmaget в кластере k8s-cluster number-two собирает метрики с этого кластера и отправляет их VMAgent_gateway(4).
-
Node Exporters развёрнуты на серверах, виртуальных машинах и собирают с них метрики. Эти метрики забирает VMAgent_Gateway(4).
-
Метрики кластера, собранные через victoria-kube-state-metrics. Эти метрики также забирает VMAgent_Gateway(4).
-
VMagent_gateway. Забирает метрики со всех сущностей, которые есть в scrape конфигах, также принимает метрики от других агентов. Агент именно из victoria-metrics-k8s-stack выбран как gateway, потому что при развёртывании оператора, сущности оператора автоматически собирают метрики кластера, а также все таргеты в скрейпах по дефолту обрабатывает именно этот агент. VMagent_gateway через remoteWrite пушит все метрики в VMAgent_raw(6).
-
RAW-Cluster. Кластер для хранения сырых (необработанных) метрик. Компоненты:
-
VMinsert_raw: Вставляет сырые метрики полученные от VMAgent_raw(6) в хранилище.
-
VMStorage_raw: Хранилище сырых метрик.
-
VMSelect_raw: Позволяет выполнять запросы сырых метрик, хранящихся в VMStorage_raw
-
-
VMAgent_raw. Получает сырые метрики от VMAgent_gateway и через remoteWrite пушит их в VMInsert_raw и VMAgent_aggr. На VMAgent_raw полностью отключены все скрейпы.
-
VMAgent_aggr. Получает сырые метрики от VMAgent_raw, агрегирует и отправляет дальше в VMInsert_aggr. Скрейпы полностью отключены.
-
AGGR-Cluster. Кластер для хранения агрегированных метрик. Компоненты:
-
VMIsert_aggr: Получает агрегированные метрики от VMAgent_aggr и отправляет в хранилище. — VMStorage_aggr: Хранилище агрегированных метрик.
-
VMSelect_aggr: Позволяет выполнять запросы агрегированных метрик, хранящимся в VMStorage_aggr.
-
-
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-чарты
Для решения задачи было принято решение использовать вот такие чарты:
-
victoria-metrics-k8s-stack-0.36.0 – версия 0.36 (appVersion: v1.110.0), покрывает части 4, 5, схема 2.
-
victoria-metrics-cluster – версия 0.18.1(appVersion: v1.110.0), покрывает часть 8, схема 2.
-
victoria-metrics-agent – версия 0.16.2(appVersion: v1.110.0), использован в 1, 6 и 7 пунктах, схема 2.
Про развёртывание
Для развёртывания чартов используется 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"
Картинки результата.
Сейчас настало время посмотреть, что же вышло по итогу.
Вот так сейчас выглядят агрегированные метрики на тестовом приложении:
И так выглядят сырые метрики:
Все вышло так, как и планировалось. Но если смотреть в Grafana, то могут возникнуть сомнения, ведь точки на дашборде с агрегированными метриками есть не только на 5 минутах, а также на промежутках, вот так:
Поэтому проверим через vmui c raw-query, чтобы убедиться наверняка:
Вот теперь точно всё по плану.
Вывод.
Наше решение с разделением метрик на сырые (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/
Добавить комментарий