VictoriaMetrics 是一款为大规模监控场景设计的快速、经济且可扩展的时间序列数据库。它最吸引人的地方在于,可以无缝融入你现有的 Prometheus 生态,提供更优的性能和更低的资源消耗。
想用更少的硬件成本处理海量监控数据?不妨在 云栈社区 看看大伙儿在 数据库与中间件选型 上的实战经验。
核心特性一览
VictoriaMetrics 的亮点很多,如果你正被 Prometheus 的存储瓶颈困扰,这些特性值得仔细看看:
- 长期存储神器:可直接作为 Prometheus 的远端存储,也支持在 Grafana 中直接通过 Prometheus 或 Graphite API 查询,替代方案非常灵活。
- 运维极简:它就是一个独立的二进制文件,没有外部依赖。所有数据都乖乖待在一个由
-storageDataPath 指定的目录里。备份与恢复依靠 vmbackup / vmrestore 工具直传 S3 或 GCS,简单高效。
- 查询增强:实现了兼容 PromQL 的查询语言 MetricsQL,并带来了功能增强。最方便的是全局查询视图,多个 Prometheus 实例的数据都灌入 VictoriaMetrics 后,只需一次查询就能看到全貌。
- 性能与压缩碾压:处理高基数时间序列时,内存占用仅为 InfluxDB 的 1/10,或 Prometheus/Thanos/Cortex 的 1/7。数据压缩率惊人,相比 TimescaleDB 能多塞下 70 倍的数据点,存储成本大幅降低。
- 协议兼容性强:数据摄入方式五花八门,几乎覆盖了你所有可能的场景:
- Prometheus 抓取协议与 Remote Write API
- 基于 HTTP、TCP 和 UDP 的 InfluxDB 线路协议
- Graphite 纯文本协议及 OpenTSDB 的多种数据推送方式
- JSON 行格式、任意 CSV 数据及原生二进制格式
- 天生抗故障:即便遭遇 OOM、物理重置或
kill -9 这类非正常关机,它的文件结构也能有效防止数据损坏。
- 集群支持:提供开源集群版本,可轻松应对 Kubernetes、APM 及物联网这类大规模数据洪流。
组件架构
单机版
单机部署最简单,核心可执行文件就是 VictoriaMetrics。你只需关注两个关键参数:
-storageDataPath:数据文件存放的位置。
-retentionPeriod:数据保留时长,默认 1 个月。注意,旧数据并非到期立即删除,而是会再额外保留大约一个月后开始清理。例如,1 月 1 号的数据会在 3 月 1 号后被移除。
单机版默认监听 8428 端口。
要让 Prometheus 把数据写到 VictoriaMetrics,只需在 prometheus.yml 中增加 remote_write 配置:
remote_write:
- url: http://<victoriametrics-addr>:8428/api/v1/write
此时,Prometheus 会同时将数据存入本地存储和远程的 VictoriaMetrics,互不干扰。也就是说,即使远程写入的目标暂时不可用,你依然可以在本地保留的数据中查询,安全系数很高。
如果打算把多个 Prometheus 实例的数据集中起来,务必给每个实例打上唯一的标签以便区分。在 Prometheus 配置文件的 global 块中加上:
global:
external_labels:
datacenter: dc-123
这样,所有发送到 VictoriaMetrics 的样本上都会带上 datacenter=dc-123,之后你就可以按这个标签来过滤和聚合数据了。这个标签名称可以自定义,只要保证每个 Prometheus 实例的值唯一即可。
对于高并发的写入场景(比如每秒采样数超过 20 万),建议对 remote_write 队列做些调优:
remote_write:
- url: http://<victoriametrics-addr>:8428/api/v1/write
queue_config:
max_samples_per_send: 10000
capacity: 20000
max_shards: 30
需要留意的是,开启远程写入会让 Prometheus 自身的内存消耗增加大约 25%。如果发现内存有点吃不消,可以适当调低 max_samples_per_send 和 capacity 这两个紧密相关的参数,找到最适合你环境的平衡点。
单机版实操
这里以 Docker Compose 为例,快速跑通一个最小化的监控栈。
1. 前置准备
先创建好数据目录:
mkdir prom_config prom_data grafana_data victoria-metrics-data
2. 编排文件 (docker-compose.yml)
version: '3'
services:
victoriametrics-server:
container_name: victoriametrics
image: victoriametrics/victoria-metrics:latest
ports:
- "8428:8428"
user: root
volumes:
- /etc/localtime:/etc/localtime:ro
- ./victoria-metrics-data:/victoria-metrics-data
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
prometheus-server:
image: prom/prometheus:latest
container_name: prometheus
hostname: prometheus
restart: always
# user: "1000:1000"
user: root
ports:
- "9090:9090"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./prom_config:/etc/prometheus
- ./prom_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=600s'
- '--storage.tsdb.no-lockfile'
- '--log.level=info'
- '--web.enable-lifecycle'
- '--query.max-concurrency=100'
- '--web.max-connections=1024'
- '--log.format=json'
- '--web.enable-admin-api'
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
# command: ["--storage.tsdb.retention.time=10m"]
grafana:
container_name: grafana
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
user: root
3. Prometheus 配置 (prometheus.yml)
这个文件放在 ./prom_config 目录下,核心在于 remote_write 和 external_labels 的设置。
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# 增加扩展的标签
external_labels:
bl_monitor: os_monitor
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090", "you_address_ip:8428"]
# 设置victoriametrics
remote_write:
- url: http://you_address_ip:8428/api/v1/write
集群版
走到生产环境,单点总会遇到天花板。集群版才是重头戏。VictoriaMetrics 的集群组件分工相当清晰:
- vminsert:数据写入的“大门”,接收来自各种数据源的数据,默认端口 8480。前方需要架设负载均衡器,如 vmauth 或 Nginx。
- vmselect:数据查询的“大脑”,负责响应用户查询请求,默认端口 8481。同样需要负载均衡器在前。
- vmstorage:数据的“最终归宿”,存储所有底层数据。高可用的底线是至少两个节点。默认端口 8482。
- vmagent:轻量级数据采集器,可以看作 Prometheus 的替代品,比 Prometheus 更节省资源。
- vmalert:告警组件,需要依赖 Alertmanager。
- vmauth:一个专为 vminsert 和 vmselect 设计的轻量级负载均衡器。
集群的关键在于存储节点间的对等关系,你要在所有 vminsert 和 vmselect 节点的启动命令中,显式配好所有 vmstorage-* 节点的地址。扩容或缩容时,也必须同步更新这些配置。
集群版实操
下面的示例使用 vmagent 替代了 Prometheus 来抓取指标,配置时需要注意为数据指定租户 ID。
1. 前置准备
mkdir grafanadata strgdata-1 strgdata-2 vmagentdata
2. 编排文件 (docker-compose.yml)
version: '3.5'
services:
vmagent:
container_name: vmagent
image: victoriametrics/vmagent
depends_on:
- "vminsert"
ports:
- 8429:8429
volumes:
- ./vmagentdata:/vmagentdata
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--promscrape.config=/etc/prometheus/prometheus.yml'
- '--remoteWrite.url=http://vminsert:8480/insert/0/prometheus/'
restart: always
grafana:
container_name: grafana-1
image: grafana/grafana:8.3.2
depends_on:
- "vmselect"
ports:
- 3001:3000
restart: always
volumes:
- ./grafanadata:/var/lib/grafana
vmstorage-1:
container_name: vmstorage-1
image: victoriametrics/vmstorage
ports:
- 8482
- 8400
- 8401
volumes:
- ./strgdata-1:/storage
command:
- '--storageDataPath=/storage'
restart: always
vmstorage-2:
container_name: vmstorage-2
image: victoriametrics/vmstorage
ports:
- 8482
- 8400
- 8401
volumes:
- ./strgdata-2:/storage
command:
- '--storageDataPath=/storage'
restart: always
vminsert:
container_name: vminsert
image: victoriametrics/vminsert
depends_on:
- "vmstorage-1"
- "vmstorage-2"
command:
- '--storageNode=vmstorage-1:8400'
- '--storageNode=vmstorage-2:8400'
ports:
- 8480
restart: always
vmselect:
container_name: vmselect
image: victoriametrics/vmselect
depends_on:
- "vmstorage-1"
- "vmstorage-2"
command:
- '--storageNode=vmstorage-1:8401'
- '--storageNode=vmstorage-2:8401'
ports:
- 8481:8481
restart: always
# vmalert:
# container_name: vmalert
# image: victoriametrics/vmalert
# depends_on:
# - "vmselect"
# ports:
# - 8880:8880
# volumes:
# - ./alerts.yml:/etc/alerts/alerts.yml
# command:
# - '--datasource.url=http://vmselect:8481/select/0/prometheus'
# - '--remoteRead.url=http://vmselect:8481/select/0/prometheus'
# - '--remoteWrite.url=http://vminsert:8480/insert/0/prometheus'
# - '--notifier.url=http://alertmanager:9093/'
# - '--rule=/etc/alerts/*.yml'
# # display source of alerts in grafana
# - '-external.url=http://127.0.0.1:3000' #grafana outside container
# # when copypaste the line below be aware of '$$' for escaping in '$expr'
# - '--external.alert.source=explore?orgId=1&left=["now-1h","now","VictoriaMetrics",{"expr":"{{$$expr|quotesEscape|crlfEscape|queryEscape}}"},{"mode":"Metrics"},{"ui":[true,true,true,"none"]}]'
# restart: always
# alertmanager:
# container_name: alertmanager
# image: prom/alertmanager
# volumes:
# - ./alertmanager.yml:/config/alertmanager.yml
# command:
# - '--config.file=/config/alertmanager.yml'
# ports:
# - 9093:9093
# restart: always
3. vmagent 配置 (prometheus.yml)
配合集群版使用的抓取配置,targets 指向了集群内部的各个组件。
# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# 增加扩展的标签
external_labels:
bl_monitor: os_monitor
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["vmagent:8429", "vmstorage-1:8482", "vmstorage-2:8482", "vmselect:8481", "vminsert:8480"]
- job_name: "prometheus-consul"
consul_sd_configs:
- server: 'consul_address_ip:8500'
datacenter: prometheus
services: ['Linux']
relabel_configs:
- source_labels: ['__meta_consul_node']
regex: '(1.1.11.*)'
action: keep