Давно і багато чув про 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
: відповідає за обробку вхідних запитів на вибірку даних та збор даних з нодvmstorage
vminsert
: відповідає за прийом метрик та розподіл даних по нодам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