Давно і багато чув про VictoriaMetrics, і нарешті настав час, коли її можна спробувати.
Отже, в двох словах – VictoriaMetrics це “Prometheus на стероідах”, і повністю з ним сумісна – може використовувати його файли конфігурації, експортери, PromQL тощо.
Тож як для людини, яка завжди користувалась Prometheus, перше питання – в чьому різниця? Єдине, що пам’ятаю, це те, що VictoriaMetrics начебто вміє в anomaly detection, чого не вистачало в Prometheus – давно хотілось додати.
В Google порівнянь не так багато, але знайшлись такі:
- System Properties Comparison Prometheus vs. VictoriaMetrics – загальна інформація по обох системах
- Prometheus vs VictoriaMetrics benchmark on node_exporter metrics – VictoriaMetrics набагато менше використовує диск і пам’ять (а ChatGPT ще говорить, що і для зберігання даних VictoriaMetrics використовує менше диску)
- What is the difference between vmagent and Prometheus? та What is the difference between vmagent and Prometheus agent? – FAQ від самої VictoriaMetrics
- Prominent features – трохи документації від VictoriaMetrics про її можливості
З цікавого:
- підримує Pull та Push моделі (на відміну від Prometheus, якому для push потрібен Pushgateway)
- можна налаштувати Prometheus з remote write у VictoriaMetrics, тобто з Prometheus писати дані у VictoriaMetrics
- VictoriaMetrics має концепцію “неймспейсів” – можна мати ізольовані середовища для метрик, див. Multitenancy
- має власний MetricsQL з ширшими ніж у PromQL можливостями
- для знайомства є VictoriaMetrics playground
- для AWS є Managed VictoriaMetrics
Отже, сьогодні глянемо на архітектуру і компоненти, запустимо VictoriaMetrics з Docker Compose, налаштуємо збір метрик с Prometheus exporters, глянемо як там з алертами, і підключимо Grafana.
Prometheus з Alertmanager, пачка експортерів та Grafana вже є, наразі запущені просто через Docker Compose на AWS EC2, туди ж додамо інстанс VictoriaMetrics. Тобто основна ідея – замінити Prometheus на VictoriaMetrics.
З того, що побачив поки запускав VictoriaMetrics – виглядає прям дуже цікаво. Більше можливостей по функціям, по шаблонам алертів, сам UI дає більше можливостей для роботи з метриками. Спробуємо його використати замість Prometehus в нашому проекті, подивимось, як воно буде. Правда, якихось прикладів в тому ж Гуглі небагато, проте ChatGPT може допомогти.
Зміст
Архітектура VictoriaMetrics
VictoriaMetrics має cluster version та single-node version. Для невеликих проектів до мільйона метрик в секунду рекомендується використовувати single node, але у кластер-версії гарно описана загальна архітектура.
Основні сервіси та компоненти VictoriaMetrics:
vmstorage: відповідає за зберігання даних та відповіді на запит даних клієнтами (vmselect)vmselect: відповідає за обробку вхідних запитів на вибірку даних та збор даних з нодvmstoragevminsert: відповідає за прийом метрик та розподіл даних по нодамvmstorageу відповідності до імен та лейбл цих метрикvmui: Web UI для доступу к даним і параметрам конфігурацїvmalert: обробляє алерти з файлу конфігурації та відправляє їх до Alertmanagervmagent: займається збором метрик з різних джерел, таких як експортери Prometheus, їхнє фільтрування та релейбл, і зберігання у сховищі даних (самій VictoriaMetrics або черезremote_writeпротокол Prometheus)vmanomaly: VictoriaMetrics Anomaly Detection – сервіс, який постійно сканує дані у VictoriaMetrics і за допомогою механізмів machine learning виявляє несподівані зміни, які можна використовувати у алертахvmauth: простий auth proxy, роутер та лоад-балансер для VictoriaMetrics.
Запуск VictoriaMetrics з Docker Compose
Отже, як ми можемо використати VictoriaMetrics у випадку, якщо вже є Prometheus та його експортери?
- можемо налаштувати Prometheus слати метрики у VictoriaMetrics, див. Prometheus setup (майте на увазі, що
remote_writeна Prometheus-інстансі збільшить споживання ресурсів ЦПУ та диску на 25%) – не бачу сенсу в нашому випадку, але можливо буде корисним у разі використання якогось KubePrometehusStack - можемо налаштувати VictoriaMetrics на збір даних з експортерів Prometheus, див. How to scrape Prometheus exporters such as node-exporter, тобто як раз зробити те, що хочеться зараз – замінити Prometheus на VictoriaMetrics з мінімальними змінами у конфігурації Prometheus
Приклад Docker Compose файлу – docker-compose.yml.
Що ми в ньому маємо:
vmagent: збирає метрики з експортерів,див опції у Advanced usagevictoriametrics: зберігає дані, див опції у List of command-line flagsvmalert: працює з алертами, див опції у Flagsalertmanager: старий знайомий) приймає алерти відvmalert
Давайте почнемо з контейнерів vmagent та victoriametrics, алерти підключимо пізніше.
Тут приклад з усіма сервісами окрім експортерів Prometheus:
version: '3.8'
volumes:
prometheus_data: {}
grafana_data: {}
vmagentdata: {}
vmdata: {}
services:
prometheus:
image: prom/prometheus
restart: always
volumes:
- ./prometheus:/etc/prometheus/
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
- '--web.external-url=http://100.***.****.197:9090/'
ports:
- 9090:9090
- alertmanager:alertmanager
alertmanager:
image: prom/alertmanager
restart: always
ports:
- 9093:9093
volumes:
- ./alertmanager/:/etc/alertmanager/
command:
- '--config.file=/etc/alertmanager/config.yml'
- '--storage.path=/alertmanager'
grafana:
image: grafana/grafana
user: '472'
restart: always
environment:
GF_INSTALL_PLUGINS: 'grafana-clock-panel,grafana-simple-json-datasource'
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning/:/etc/grafana/provisioning/
env_file:
- ./grafana/config.monitoring
ports:
- 3000:3000
depends_on:
- prometheus
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
victoriametrics:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:v1.91.2
ports:
- 8428:8428
volumes:
- vmdata:/storage
command:
- "--storageDataPath=/storage"
- "--httpListenAddr=:8428"
# - "--vmalert.proxyURL=http://vmalert:8880"
vmagent:
container_name: vmagent
image: victoriametrics/vmagent:v1.91.2
depends_on:
- "victoriametrics"
ports:
- 8429:8429
volumes:
- vmagentdata:/vmagentdata
- ./prometheus:/etc/prometheus/
command:
- "--promscrape.config=/etc/prometheus/prometheus.yml"
- "--remoteWrite.url=http://victoriametrics:8428/api/v1/write"
...
Для victoriametrics поки що закоментуємо --vmalert.proxyURL, додамо його згодом.
До vmagent підключаємо каталог ./prometheus – в ньому маємо файл prometheus.yaml з конфігурацією srape_jobs, та файли параметрів експортерів (наприклад – ./prometheus/blackbox.yml та /prometheus/blackbox-targets/targets.yaml для Blackbox Exporter).
У --remoteWrite.url вказуємо, куди будемо писати отримані метрики – до інстансу VictoriaMetrics.
Запускаємо:
[simterm]
# docker compose up
[/simterm]
Якщо перейти без URI, тобто просто на domain.com/ – то видасть всі доступні шляхи, дуже прям зручно:
field evaluation_interval not found in type promscrape.GlobalConfig
Але vmagent не запустився:
[simterm]
2023-06-05T09:38:31.376Z fatal VictoriaMetrics/lib/promscrape/scraper.go:117 cannot read "/etc/prometheus/prometheus.yml": cannot parse Prometheus config from "/etc/prometheus/prometheus.yml": cannot unmarshal data: yaml: unmarshal errors: line 4: field evaluation_interval not found in type promscrape.GlobalConfig line 13: field rule_files not found in type promscrape.Config line 19: field alerting not found in type promscrape.Config; pass -promscrape.config.strictParse=false command-line flag for ignoring unknown fields in yaml config
[/simterm]
Окей, відключимо strictParse – додаємо --promscrape.config.strictParse=false:
...
command:
- "--promscrape.config=/etc/prometheus/prometheus.yml"
- "--remoteWrite.url=http://victoriametrics:8428/api/v1/write"
- "--promscrape.config.strictParse=false"
Перезапускаємо сервіси, та заглянемо на порт 8429, vmagent – теж є лінки :
Перевіряємо таргети – вони є, тобто vmagent зчитав файл prometheus.yaml, але не всі працюють, наприклад – Sentry експортер є, YACE є, а от blackbox, node_exporter та cAdvisor не бачить:
А чому?
Ага… Не бачить тих, у кого sd_configs, тобто динамічний сервіс-діскавері:
... - job_name: 'cadvisor'
# Override the global default and scrape targets from this job every 5 seconds.
scrape_interval: 5s
dns_sd_configs:
- names:
- 'tasks.cadvisor'
type: 'A'
port: 8080
...
Хоча наче має вміти – Supported service discovery configs.
Глянемо логи vmagent.
error in A lookup for “tasks.cadvisor”: lookup tasks.cadvisor on 127.0.0.11:53: no such host
А логи кажуть, що контейнер з vmagent не може отримати A-запис з DNS:
[simterm]
... vmagent | 2023-06-05T10:04:10.818Z error VictoriaMetrics/lib/promscrape/discovery/dns/dns.go:163 error in A lookup for "tasks.cadvisor": lookup tasks.cadvisor on 127.0.0.11:53: no such host vmagent | 2023-06-05T10:04:10.821Z error VictoriaMetrics/lib/promscrape/discovery/dns/dns.go:163 error in A lookup for "tasks.node-exporter": lookup tasks.node-exporter on 127.0.0.11:53: no such host ...
[/simterm]
Читаємо документацію по dns_sd_configs, де говориться про “# names must contain a list of DNS names to query“, але в мене зараз job описана з names = tasks.container_name, див. Container discovery.
Спробуємо вказати просто ім’я, тобто cadvisor замість tasks.cadvisor:
...
- job_name: 'cadvisor'
dns_sd_configs:
- names:
# - 'tasks.cadvisor'
- 'cadvisor'
type: 'A'
port: 8080
...
А job_name: 'prometheus' просто вимикаємо – вона нам не потрібна.
І тепер всі таргети з’явились:
VictoriaMetrics та Grafana
Тепер давайте спробуємо використати VictoriaMetrics як data source у Grafana.
В принципі, тут все робиться однаково з Prometheus, використовуючи той же тип data source.
Додаємо новий data source з типом Prometheus, в URL вказуємо http://victoriametrics:8428:
Обновлюємо графік – вибираємо щойно доданий data source:
І тепер можемо використовувати функцію sort_by_label_numeric, якої не вистачало у пості Prometheus: GitHub Exporter – пишемо власний експортер для GitHub API.
З Prometheus ця панель виглядає так:
А з VictoriaMetrics та sort_by_label_numeric – так:
Добре, наче все працює.
Можемо пробувати роботу з алертами.
VictoriaMetrics та Alertmanager
Отже, зара маємо запущений Alertmanager та Prometheus.
У prometheus.yaml маємо вказаний файл з алертами:
... rule_files: - 'alert.rules' ...
Що нам треба – це запустити vmalert, якому вкажемо “бекенд” у вигляді Alertmanager, якому він буде слати алерти, та сам файл з алертами у форматі Prometheus.
Як і сама VictoriaMetrics, vmalert має дещо ширші можливості, ніж Prometheus, наприклад – зберігає статус алертів, тож рестарт контейнеру не сбиває silenced алерти. Ще є зручна змінна $for для шаблонів, в якій передається значення for з алерту, і можемо мати щось таке:
...
for: 5m
annotations:
description: |-
{{ if $value }} *Current latency*: `{{ $value | humanize }}` milliseconds {{ end }} during `{{ $for }}` minutes
...
Також є підримка httpAuth, є можливість виконати запит алерту з query та багато іншого, див. Template functions.
Додаємо vmalert в docker-compose.yaml:
...
vmalert:
container_name: vmalert
image: victoriametrics/vmalert:v1.91.2
depends_on:
- "victoriametrics"
- "alertmanager"
ports:
- 8880:8880
volumes:
- ./prometheus/alert.rules:/etc/alerts/alerts.yml
command:
- "--datasource.url=http://victoriametrics:8428/"
- "--remoteRead.url=http://victoriametrics:8428/"
- "--remoteWrite.url=http://victoriametrics:8428/"
- "--notifier.url=http://alertmanager:9093/"
- "--rule=/etc/alerts/*.yml"
Тут у datasource.url вказуємо, звідки брати метрики для перевірки у алертах, remoteRead.url та remoteWrite.url – де зберігати стан алертів.
У notifier.url – куди будемо слати алерти (а вже Alertmanager через свій конфіг відправить їх у Slack/Opsgenie/etc). І у rule вказуємо сам файл з алертами, який підключаємо у volumes.
Перезапускаємо контейнери з docker compose restart, и заходимо на порт 8880:
Окей, є алерт-рули.
Спробуємо тригернути тестовий алерт – і маємо новий алерт у vmalert Alerts:
Та повідомлення в Slack від Alertmanager:
Все працює.
Тепер можна відключати контейнер з Prometheus, тільки оновити depends_on у Grafana – замість prometheus вказати victoriametrics, і замінити data sources у дашбордах.
Bonus: Alertmanager Slack template
І приклад шаблону для нотіфікацій в Slack. Він ще буде перероблюватись, поки що вся система більше в стані proof of concept, але в цілому буде якось так.
Файл alertmanager/notifications.tmpl з шаблоном:
{{/* Title of the Slack alert */}}
{{ define "slack.title" -}}
{{ if eq .Status "firing" }} :scream: {{- else -}} :relaxed: {{- end -}}
[{{ .Status | toUpper -}} {{- if eq .Status "firing" -}}:{{ .Alerts.Firing | len }} {{- end }}] {{ (index .Alerts 0).Annotations.summary }}
{{ end }}
{{ define "slack.text" -}}
{{ range .Alerts }}
{{- if .Annotations.description -}}
*Description*: {{ .Annotations.description }}
{{- end }}
{{- end }}
{{- end }}
Його використання в alertmanager/config.yml:
receivers:
- name: 'slack-default'
slack_configs:
- title: '{{ template "slack.title" . }}'
text: '{{ template "slack.text" . }}'
send_resolved: true
actions:
- type: button
text: 'Grafana :grafana:'
url: '{{ (index .Alerts 0).Annotations.grafana_url }}'
- type: button
text: 'Prometheus query :mag:'
url: '{{ (index .Alerts 0).GeneratorURL }}'
- type: button
text: 'AWS dashboard :aws:'
url: '{{ (index .Alerts 0).Annotations.aws_dashboard_url }}'
Темплейт для алерту – підключається в контейнер vmalerts, див. Reusable templates:
{{ define "grafana.filter" -}}
{{- $labels := .arg0 -}}
{{- range $name, $label := . -}}
{{- if (ne $name "arg0") -}}
{{- ( or (index $labels $label) "All" ) | printf "&var-%s=%s" $label -}}
{{- end -}}
{{- end -}}
{{- end -}}
І сам алерт:
- record: aws:apigateway_integration_latency_average_sum
expr: sum(aws_apigateway_integration_latency_average) by (dimension_ApiName, tag_environment)
- alert: APIGatewayLatencyBackendProdTEST2
expr: aws:apigateway_integration_latency_average_sum{tag_environment="prod"} > 100
for: 1s
labels:
severity: info
component: backend
environment: test
annotations:
summary: "API Gateway latency too high"
description: |-
The time between when API Gateway relays a request to the backend and when it receives a response from the backend
*Environment*: `{{ $labels.tag_environment }}`
*API Gateway name*: `{{ $labels.dimension_ApiName }}`
{{ if $value }} *Current latency*: `{{ $value | humanize }}` milliseconds {{ end }}
grafana_url: '{{ $externalURL }}/d/overview/overview?orgId=1{{ template "grafana.filter" (args .Labels "environment" "component") }}'
А $externalURL отримується vmalerts з параметру --external.url=http://100.***.***.197:3000".
Корисні посилання
- VictoriaMetrics Key concepts
- Third-party articles and slides about VictoriaMetrics
- MetricsQL query with optional WITH expressions
- Monitoring at scale with Victoria Metrics
![]()










