Перейти к содержимому
HoginHogin
Назад

VictoriaMetrics вместо Prometheus+Thanos: один бинарь вместо трёх — когда это честная экономия

8 мин чтения

Prometheus отличный, пока метрики помещаются в локальный диск: две недели retention, один StatefulSet, ноль внешних зависимостей. Боль начинается с вопроса «а что случилось месяц назад?» — и к Prometheus пристраивается Thanos: sidecar, store gateway, compactor, query. VictoriaMetrics закрывает тот же сценарий одним процессом, а в июле 2026 у неё вышла LTS-линейка v1.148.0 с фиксами на год вперёд — повод честно разложить, до какого размера метрик это экономия, а где самообман.

Содержание

Открыть содержание

Чем заканчивается «просто Prometheus»

Локальный TSDB хранит блоки на PV: год retention — терабайтный диск и рестарты с холодным кэшем. HA — два Prometheus и дедуп на чтении.

Стандартный ответ — Thanos. Для терабайтов архитектура честная, но посчитайте компоненты: sidecar рядом с каждым Prometheus, store gateway (индекс по старым блокам), compactor (компакция и downsampling), query (склейка свежего и старого). Четыре-пять деплойментов с версиями и апгрейдами, плюс бакет в S3.

Прометеус+Thanos: пять компонентов ради долгого хранения — против одного процесса VictoriaMetrics

На малом кластере каждый почти пустой: store на гигабайты, query, который никто не грузит. Вы обслуживаете топологию под терабайты ради десятков гигабайт.

Что меняет VictoriaMetrics

Что из экосистемы реально нужно на малом масштабе:

Стек VictoriaMetrics: vmagent пишет в vmsingle, vmalert читает, vmbackup снимает снапшоты в S3, Grafana поверх

Порог применимости: где single, а где cluster

Оперируйте тремя числами: active time series (уникальных label-сетов), rate приёма (samples/sec) и churn (рождается и умирает серий в час).

Лестница масштаба: до 100k — single без вопросов, до 1M — зона комфорта, дальше — cluster

Оговорка про HA: single — один процесс. Бэкапы через vmbackup обязательны, а живая отказоустойчивость приёма — довод в сторону cluster-режима, а не «второго vmsingle». Мягчает буфер vmagent: пока стор недоступен, метрики копятся на диске агента.

Prometheus+Thanos против VM single

Prometheus + ThanosVM single
Компоненты хранения4–5 деплойментов1 (+CronJob бэкапа)
ХранилищеS3 + локальный TSDBPV + S3 для бэкапов
RAM стека~5–6 ГБ~1–1.5 ГБ
Диск на те же данные1×обычно 2–4× меньше
Запросы в глубинуquery + store, с задержкойодин endpoint
Смена retentionкомпакция, downsampling-retentionPeriod + рестарт
Апгрейдсогласованно 4 компонентаодин тег на стек
HA приёмадва Prometheus + дедупcluster-режим
Правила и алертыPrometheus rulesvmalert + Alertmanager, те же правила
Язык запросовPromQLMetricsQL (надмножество)

Два сценария перехода

Remote-write из существующего Prometheus. Минимальный риск: добавляете remote_write на http://vmsingle:8428/api/v1/write, укорачиваете локальный retention, правила переносите в vmalert по мере готовности. Откат — удаление одной строки. Историю старше retention перенесёт vmctl prometheus (импорт TSDB-снапшотов).

Полная замена. vmagent забирает scrape (те же kubernetes_sd-роли и relabel-конфиги), Prometheus удаляется. Минус целый стек и большая часть RAM мониторинга; цена — перенос правил. Этот сценарий и разворачиваем.

Что нужно, чтобы собрать стек в одном namespace

Весь стек — в namespace monitoring, на LTS v1.148.0 (фиксы до лета 2027): vmagent пишет в vmsingle, vmalert гоняет правила в Alertmanager, vmbackup раз в 6 часов снимает снапшот в S3, Grafana читает через один datasource.

1. Хранилище: vmsingle. Deployment с PVC и Service:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vmsingle
  namespace: monitoring
spec:
  replicas: 1
  selector: { matchLabels: { app: vmsingle } }
  template:
    metadata: { labels: { app: vmsingle } }
    spec:
      containers:
        - name: vmsingle
          image: victoriametrics/victoria-metrics:v1.148.0
          args:
            - -storageDataPath=/storage
            - -retentionPeriod=12m      # месяцы
            - -search.maxUniqueTimeseries=500000   # выше вашего числа серий
          ports: [{ containerPort: 8428 }]
          volumeMounts: [{ name: data, mountPath: /storage }]
      volumes:
        - name: data
          persistentVolumeClaim: { claimName: vmsingle-data }
---
apiVersion: v1
kind: Service
metadata:
  name: vmsingle
  namespace: monitoring
spec:
  selector: { app: vmsingle }
  ports: [{ port: 8428 }]

2. Сборщик: vmagent. Конфиг скрейпа — как у Prometheus:

apiVersion: v1
kind: ConfigMap
metadata:
  name: vmagent-config
  namespace: monitoring
data:
  scrape.yml: |
    global:
      scrape_interval: 30s
    scrape_configs:
      - job_name: kubernetes-pods
        kubernetes_sd_configs:
          - role: pod
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep
            regex: "true"
          - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
            action: replace
            regex: ([^:]+)(?::\d+)?;(\d+)
            replacement: $1:$2
            target_label: __address__
      # ноды — role: node через apiserver-proxy, конфиг один в один Prometheus

Арги агента — здесь же защита от взрыва кардинальности:

# фрагмент Deployment vmagent
image: victoriametrics/vmagent:v1.148.0
args:
  - -promscrape.config=/config/scrape.yml
  - -remoteWrite.url=http://vmsingle:8428/api/v1/write
  - -remoteWrite.tmpDataPath=/buffer      # буфер на диск
  - -remoteWrite.maxHourlySeries=300000   # кап новых серий в час
  - -remoteWrite.maxDailySeries=1000000   # и в сутки — от кривого релиза

3. Правила: vmalert. Правила из kube-prometheus-stack переезжают без правок; пример:

apiVersion: v1
kind: ConfigMap
metadata:
  name: vmalert-rules
  namespace: monitoring
data:
  rules.yaml: |
    groups:
      - name: k8s
        rules:
          - alert: PodRestartLoop
            expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
            for: 5m
            labels: { severity: warning }
# фрагмент Deployment vmalert
image: victoriametrics/vmalert:v1.148.0
args:
  - -datasource.url=http://vmsingle:8428
  - -remoteWrite.url=http://vmsingle:8428      # recording rules в VM
  - -remoteRead.url=http://vmsingle:8428       # состояние алертов
  - -notifier.url=http://alertmanager:9093     # Alertmanager ставится рядом
  - -rule=/config/*.yaml

4. Бэкапы: vmbackup по CronJob. Снапшот создаётся на стороне vmsingle:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: vmbackup
  namespace: monitoring
spec:
  schedule: "0 */6 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: vmbackup
              image: victoriametrics/vmbackup:v1.148.0
              args:
                - -snapshot.createURL=http://vmsingle:8428/snapshot/create
                - -dst=s3://metrics-backup/vmsingle
                - -storageDataPath=/storage
                - -s3.endpoint=s3.eu-central-1.amazonaws.com
              volumeMounts: [{ name: data, mountPath: /storage }]
          volumes:
            - name: data
              persistentVolumeClaim: { claimName: vmsingle-data }

Ключи S3 — переменными окружения из Secret (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY).

5. Grafana. Datasource prometheus — API совместим:

apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-datasources
  namespace: monitoring
data:
  vm.yaml: |
    apiVersion: 1
    datasources:
      - name: VictoriaMetrics
        type: prometheus
        url: http://vmsingle:8428
        isDefault: true

Кардинальность: главный враг бюджета

Кардинальность — число уникальных label-сетов. Каждый новый под и endpoint его множит, а один кривой лейбл (user_id, request_id) превращает 100k серий в 10M. Виновников находят двумя запросами:

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

Лечение — по нарастающей:

Цифры: RAM и диск

Типовой малый prod: три ноды, ~50 подов, kube-prometheus-stack с парой экспортёров — порядка 150k активных серий при интервале 30s. Порядок величин:

Итого — втрое меньше RAM на стек и вдвое-вчетверо меньше диска. Экономия не в лицензиях (всё нужное open source), а в операционке: один объект для обновления вместо пяти.

Как проверить, что всё работает

kubectl -n monitoring get pods
curl -s http://vmsingle.monitoring:8428/health
curl -s http://vmsingle.monitoring:8428/api/v1/series/count

Итог

До ~миллиона активных time series VictoriaMetrics single-binary — самый дешёвый по эксплуатации способ хранить метрики долго: один процесс, один PV, один CronJob бэкапа, в разы меньше RAM и диска, чем у Prometheus+Thanos на тех же данных. Thanos оправдан, когда кластеров много, тенантов больше одного и метрики измеряются терабайтами — там его топология необходимость, а не избыточность. Линия раздела измеримая: active time series. А чтобы рядом с метриками жили логи и трейсы — минимальный OpenTelemetry Collector мы разбирали отдельно.


Поделиться:

Следующая статья
Crossplane 2.0 и скорый EOL v1.20: облачная инфраструктура через GitOps вместо Terraform-стейта