概述
Prometheus 作为云原生监控的事实标准,几乎成为了微服务和 Kubernetes 监控的默认选择。然而,随着业务规模增长,Prometheus 的本地存储架构逐渐暴露出明显瓶颈:单机存储容量有限(默认 15 天保留期)、缺乏原生水平扩展能力、高基数场景下内存飙升、历史数据查询困难。很多团队在时间序列突破百万级别后,开始面临磁盘 IO 压力、存储成本膨胀和查询延迟增长的"三重困境"。
为解决这些问题,社区涌现了 Thanos、Cortex、VictoriaMetrics 等多种长期存储方案。其中 VictoriaMetrics(以下简称 VM)凭借卓越的压缩率、极简的运维复杂度和出色的查询性能,成为越来越多团队的首选。
将详细梳理 VictoriaMetrics 的架构设计、部署模式、数据迁移、性能调优和生产环境好的实践,帮助你在实际项目中做出正确的技术选型和落地。
为什么选择 VictoriaMetrics
Prometheus 的存储瓶颈
理解 VictoriaMetrics 的价值,首先需要明白 Prometheus 的存储瓶颈在哪里:
| 问题 | 原因 | 影响 |
|---|---|---|
| 数据保留期短 | 默认 TSDB 仅保留 15 天 | 无法做长期趋势分析 |
| 无法水平扩展 | 单实例架构,无分片机制 | 单机内存和磁盘成为硬上限 |
| 高基数内存膨胀 | 标签组合爆炸导致内存索引激增 | OOM 频发,监控不可用 |
| 全局查询困难 | 多实例数据分散 | 跨集群查询需额外方案 |
| 远程存储延迟 | remote_write 同步模型 | 网络问题导致数据丢失 |
VictoriaMetrics 的核心优势
VictoriaMetrics 的设计理念是:在完全兼容 Prometheus 生态的前提下,提供更高的性能和更低的资源消耗。
1. 卓越的数据压缩
VM 采用自研的列式存储引擎,针对时间序列数据特征深度优化。根据官方基准测试和大量社区实践,在存储相同监控数据时,VM 所需磁盘空间通常只有 Prometheus TSDB 的 1/5 到 1/7。
# 数据压缩效果对比(基于 100 万活跃时间序列,30 天数据)
存储方案 磁盘占用 压缩比 内存占用
─────────────────────────────────────────────────────────
Prometheus (本地) 350 GB 1x 8 GB
Thanos (S3) 120 GB 2.9x 6 GB (含 Sidecar)
VictoriaMetrics 55 GB 6.4x 3 GB
VictoriaMetrics (集群) 58 GB 6.0x 3.2 GB (总计)
数据来源:VictoriaMetrics 官方基准测试及社区实践报告。实际效果因数据特征而异,建议根据自身场景测试。
2. 极简的运维复杂度
与 Thanos 的多组件架构(Sidecar、Store、Compactor、Query、Receiver、Rule)和 Cortex 的微服务架构(Distributor、Ingester、Querier、Compactor、Store Gateway、Ruler、Alertmanager)相比,VM 的架构极其简洁:
| 方案 | 核心组件数 | 外部依赖 | 运维复杂度 |
|---|---|---|---|
| Thanos | 6+ | 对象存储 (S3/MinIO) | 高 |
| Cortex | 7+ | 对象存储 + DynamoDB/etcd | 很高 |
| VictoriaMetrics (单节点) | 1 | 无 | 极低 |
| VictoriaMetrics (集群) | 3 | 无 | 低 |
3. 高性能查询
VM 高效利用所有可用 CPU 核心进行并行处理,单实例可处理每秒数百万数据点的写入和数十亿行的查询扫描。
4. 多协议兼容
# VictoriaMetrics 支持的数据接入协议
Pull 模式(兼容 Prometheus):
└── vmagent → 抓取 Prometheus exporters → 写入 VM
Push 模式:
├── Prometheus remote_write → VM(最常用)
├── Graphite plaintext protocol
├── OpenTSDB telnet/HTTP
├── InfluxDB line protocol
├── OpenTelemetry
└── CSV import
查询兼容:
├── PromQL(完全兼容)
├── MetricsQL(PromQL 超集,扩展功能)
└── Grafana 原生集成
架构设计深入分析
存储引擎
VictoriaMetrics 的核心是其自研的列式存储引擎,理解其内部机制有助于优化使用方式。
数据摄入流程:
数据摄入 → Protobuf 编码序列化
→ 内存缓冲区(batch flush)
→ 标签索引构建(倒排索引 + TSID)
→ 列式压缩写入磁盘
→ 后台合并与降采样
关键设计:
TSID(Time Series ID):VM 将标签组合映射为内部的高效 TSID,避免每次查询都扫描全部标签。这比 Prometheus 的 label index 更高效。
共享字符串池:相同的标签值在内存中只存储一份,通过引用复用,大幅降低高基数场景下的内存消耗。
延迟加载:查询时只加载所需的数据块,而非整个时间序列,减少 IO 开销。
列式压缩:每个数据列(时间戳、值、标签)独立压缩,针对不同数据类型使用最优压缩算法。
存储目录结构:
/var/lib/victoria-metrics-data/
├── data/
│ ├── small/ # 小表分区(近期数据)
│ │ ├── 2024_01/ # 按月分区的数据块
│ │ │ ├── index.bin # 倒排索引
│ │ │ ├── timestamps.bin
│ │ │ └── values.bin
│ │ └── ...
│ ├── big/ # 大表分区(历史数据)
│ │ └── ...
│ └── indexdb/ # 索引数据库
│ ├── index.bin
│ └── metadata.json
├── metadata/
│ └── ...
└── snapshots/ # 快照(备份用)
└── ...
集群架构组件
VictoriaMetrics 集群版由三个核心组件组成:
┌──────────────┐
│ vmagent │ (可选:数据采集/分片/复制)
│ (N 个实例) │
└──────┬───────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ vminsert │ │ vminsert │ │ vminsert │
│ (实例 1) │ │ (实例 2) │ │ (实例 N) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────┼────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ vmstorage │ │ vmstorage │ │ vmstorage │
│ (节点 1) │ │ (节点 2) │ │ (节点 N) │
│ 数据存储 │ │ 数据存储 │ │ 数据存储 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────┼────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ vmselect │ │ vmselect │ │ vmselect │
│ (实例 1) │ │ (实例 2) │ │ (实例 N) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────┼────────────────┘
│
┌─────┴──────┐
│ Grafana │
│ / Client │
└────────────┘
组件职责:
| 组件 | 职责 | 无状态 | 可水平扩展 |
|---|---|---|---|
| vminsert | 接收写入请求,路由到 vmstorage 节点 | 是 | 是 |
| vmstorage | 数据存储和查询执行 | 否(有状态) | 是(分片) |
| vmselect | 接收查询请求,从 vmstorage 获取并合并结果 | 是 | 是 |
| vmagent | 数据采集、分片、复制(可选) | 是 | 是 |
| vmalert | 告警规则评估(可选) | 是 | 是 |
| vmbackup | 数据备份(可选) | 是 | - |
关键设计决策:
- vminsert 和 vmselect 是无状态的,可以自由扩展
- vmstorage 是有状态的,通过一致性哈希分片,扩容时需要 rebalance
- vminsert 到 vmstorage 的路由使用一致性哈希,保证相同时间序列始终写入同一 storage 节点
- vmselect 查询时需要向所有 vmstorage 节点发起查询并合并结果
部署实践
单节点部署
适合中小规模(100 万以下活跃时间序列)或测试环境。
#!/bin/bash
# VictoriaMetrics 单节点部署脚本
# 下载二进制
VM_VERSION="v1.115.0"
wget "https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/${VM_VERSION}/victoria-metrics-linux-amd64-v${VM_VERSION#v}.tar.gz"
tar -xzf "victoria-metrics-linux-amd64-v${VM_VERSION#v}.tar.gz"
# 创建数据目录
mkdir -p /var/lib/victoria-metrics-data
# 启动单节点
./victoria-metrics-prod \
-storageDataPath=/var/lib/victoria-metrics-data \
-retentionPeriod=90d \
-httpListenAddr=:8428 \
-memory.allowedBytes=4GB \
-search.maxConcurrentQueries=8 \
> /var/log/victoria-metrics.log 2>&1 &
echo "VictoriaMetrics 单节点已启动,监听 8428 端口"
systemd 服务配置:
# /etc/systemd/system/victoria-metrics.service
[Unit]
Description=VictoriaMetrics Single Node
After=network.target
[Service]
Type=simple
User=victoria-metrics
Group=victoria-metrics
ExecStart=/usr/local/bin/victoria-metrics-prod \
-storageDataPath=/var/lib/victoria-metrics-data \
-retentionPeriod=90d \
-httpListenAddr=:8428 \
-memory.allowedBytes=4GB
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
配置 Prometheus 远程写入:
# prometheus.yml — 添加 remote_write 配置
global:
scrape_interval: 15s
evaluation_interval: 15s
remote_write:
- url: "http://victoria-metrics:8428/api/v1/write"
queue_config:
capacity: 10000
max_samples_per_send: 2000
batch_send_deadline: 5s
min_backoff: 1s
max_backoff: 30s
# 高可用场景可配置多个远程写入端点
# remote_timeout: 30s
# 保留原有抓取配置不变
scrape_configs:
- job_name: "node-exporter"
static_configs:
- targets: ["node-exporter:9100"]
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
集群部署
适合大规模(100 万以上活跃时间序列)或需要高可用场景。
Docker Compose 部署示例:
# docker-compose.yml
version: '3.8'
services:
# --- vmstorage 节点(有状态,需持久化) ---
vmstorage-1:
image: victoriametrics/vmstorage:v1.115.0-cluster
command:
- '--storageDataPath=/storage'
- '--retentionPeriod=180d'
- '--httpListenAddr=:8482'
volumes:
- vmstorage-1-data:/storage
ports:
- "8482"
restart: unless-stopped
vmstorage-2:
image: victoriametrics/vmstorage:v1.115.0-cluster
command:
- '--storageDataPath=/storage'
- '--retentionPeriod=180d'
- '--httpListenAddr=:8482'
volumes:
- vmstorage-2-data:/storage
ports:
- "8482"
restart: unless-stopped
# --- vminsert 节点(无状态) ---
vminsert-1:
image: victoriametrics/vminsert:v1.115.0-cluster
command:
- '--httpListenAddr=:8480'
- '--storageNode=vmstorage-1:8400'
- '--storageNode=vmstorage-2:8400'
ports:
- "8480"
depends_on:
- vmstorage-1
- vmstorage-2
restart: unless-stopped
vminsert-2:
image: victoriametrics/vminsert:v1.115.0-cluster
command:
- '--httpListenAddr=:8480'
- '--storageNode=vmstorage-1:8400'
- '--storageNode=vmstorage-2:8400'
ports:
- "8480"
depends_on:
- vmstorage-1
- vmstorage-2
restart: unless-stopped
# --- vmselect 节点(无状态) ---
vmselect-1:
image: victoriametrics/vmselect:v1.115.0-cluster
command:
- '--httpListenAddr=:8481'
- '--storageNode=vmstorage-1:8401'
- '--storageNode=vmstorage-2:8401'
ports:
- "8481"
depends_on:
- vmstorage-1
- vmstorage-2
restart: unless-stopped
vmselect-2:
image: victoriametrics/vmselect:v1.115.0-cluster
command:
- '--httpListenAddr=:8481'
- '--storageNode=vmstorage-1:8401'
- '--storageNode=vmstorage-2:8401'
ports:
- "8481"
depends_on:
- vmstorage-1
- vmstorage-2
restart: unless-stopped
# --- 负载均衡 ---
lb-insert:
image: nginx:alpine
volumes:
- ./nginx-insert.conf:/etc/nginx/nginx.conf:ro
ports:
- "8480:8480"
depends_on:
- vminsert-1
- vminsert-2
restart: unless-stopped
lb-select:
image: nginx:alpine
volumes:
- ./nginx-select.conf:/etc/nginx/nginx.conf:ro
ports:
- "8481:8481"
depends_on:
- vmselect-1
- vmselect-2
restart: unless-stopped
# --- Grafana ---
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3000:3000"
restart: unless-stopped
volumes:
vmstorage-1-data:
vmstorage-2-data:
Nginx 负载均衡配置(写入端):
# nginx-insert.conf
events {}
http {
upstream vminsert {
least_conn;
server vminsert-1:8480;
server vminsert-2:8480;
}
server {
listen 8480;
location / {
proxy_pass http://vminsert;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
}
Nginx 负载均衡配置(查询端):
# nginx-select.conf
events {}
http {
upstream vmselect {
least_conn;
server vmselect-1:8481;
server vmselect-2:8481;
}
server {
listen 8481;
location / {
proxy_pass http://vmselect;
proxy_set_header Host $host;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
}
Kubernetes 部署(VictoriaMetrics Operator)
生产环境推荐使用 VictoriaMetrics Operator 管理 Kubernetes 上的 VM 集群。
# vmcluster.yaml — 使用 VictoriaMetrics Operator
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMCluster
metadata:
name: vm-cluster
namespace: monitoring
spec:
retentionPeriod: "180d"
replicationFactor: 2
# vmstorage 配置
vmstorage:
replicaCount: 3
storageDataPath: "/vm-data"
storage:
volumeClaimTemplate:
spec:
storageClassName: fast-ssd
resources:
requests:
storage: 500Gi
resources:
limits:
cpu: 4
memory: 16Gi
requests:
cpu: 2
memory: 8Gi
# vminsert 配置
vminsert:
replicaCount: 2
resources:
limits:
cpu: 2
memory: 4Gi
requests:
cpu: 1
memory: 2Gi
# vmselect 配置
vmselect:
replicaCount: 2
resources:
limits:
cpu: 2
memory: 4Gi
requests:
cpu: 1
memory: 2Gi
cacheMountPath: "/cache"
storage:
volumeClaimTemplate:
spec:
resources:
requests:
storage: 10Gi
---
# vmagent 配置 — 替代 Prometheus 抓取
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
name: vm-agent
namespace: monitoring
spec:
replicaCount: 2
serviceScrapeNamespaceSelector: {}
podScrapeNamespaceSelector: {}
nodeScrapeNamespaceSelector: {}
staticScrapeNamespaceSelector: {}
remoteWrite:
- url: "http://vm-cluster-vminsert.monitoring.svc:8480/insert/0/prometheus/api/v1/write"
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
---
# vmalert 配置 — 告警规则评估
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAlert
metadata:
name: vm-alert
namespace: monitoring
spec:
replicaCount: 2
datasource:
url: "http://vm-cluster-vmselect.monitoring.svc:8481/select/0/prometheus"
notifier:
url: "http://alertmanager.monitoring.svc:9093"
evaluationInterval: "30s"
ruleNamespaceSelector: {}
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
数据采集与迁移
使用 vmagent 替代 Prometheus 抓取
vmagent 是 VictoriaMetrics 的数据采集组件,可以直接抓取 Prometheus exporters,支持分片和复制,是生产环境中替代 Prometheus 的理想方案。
# vmagent 配置示例
global:
scrape_interval: 15s
external_labels:
cluster: "production"
region: "us-east-1"
# 抓取配置(与 Prometheus 完全兼容)
scrape_configs:
- job_name: "kubernetes-nodes"
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: "(.*):.*"
target_label: __address__
replacement: "${1}:9100"
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
# 远程写入 VictoriaMetrics
remote_write:
- url: "http://vminsert:8480/insert/0/prometheus/api/v1/write"
# 高可用:写入多个 vminsert 实例
# vmagent 会自动处理重复数据
vmagent 的高级特性——分片抓取:
# 多实例 vmagent 分片抓取(每个实例只抓取一部分目标)
# 实例 1
./vmagent-prod \
-promscrape.config=/etc/vmagent/scrape.yml \
-remoteWrite.url=http://vminsert:8480/insert/0/prometheus/api/v1/write \
-promscrape.cluster.membersCount=2 \
-promscrape.cluster.memberNum=0
# 实例 2
./vmagent-prod \
-promscrape.config=/etc/vmagent/scrape.yml \
-remoteWrite.url=http://vminsert:8480/insert/0/prometheus/api/v1/write \
-promscrape.cluster.membersCount=2 \
-promscrape.cluster.memberNum=1
vmagent 从 v1.86 开始原生支持
-remoteWrite.shardByURL,从 v1.138.0 进一步将数据分发算法升级为一致性哈希,大幅降低节点变更时的数据重分配比例。
从 Prometheus 迁移历史数据
如果要从已有 Prometheus 实例迁移历史数据到 VictoriaMetrics,有几种方式:
方式一:使用 vmrestore 从快照恢复
# 1. 在 Prometheus 端创建 TSDB 快照
curl -XPOST http://prometheus:9090/api/v1/admin/tsdb/snapshot
# 2. 使用 vmrestore 将快照导入 VM
./vmrestore-prod \
-src=s3://my-bucket/prom-snapshots/ \
-dst=/var/lib/victoria-metrics-data/
方式二:使用 vmctl 工具迁移
# vmctl 是官方数据迁移工具,支持多种数据源
# 从 Prometheus TSDB 迁移
./vmctl-prod prometheus \
-src.address=http://prometheus:9090 \
-dst.url=http://victoria-metrics:8428 \
-dst.addr=http://victoria-metrics:8428
# 从 InfluxDB 迁移
./vmctl-prod influxdb \
-src.addr=http://influxdb:8086 \
-src.database=monitoring \
-dst.url=http://victoria-metrics:8428
# 从 OpenTSDB 迁移
./vmctl-prod opentsdb \
-src.addr=http://opentsdb:4242 \
-dst.url=http://victoria-metrics:8428
# 从远程 Prometheus 兼容存储迁移
./vmctl-prod remote \
-src.addr=http://remote-storage:9090 \
-dst.url=http://victoria-metrics:8428 \
-time-filter='{"start":"2025-01-01T00:00:00Z","end":"2026-07-01T00:00:00Z"}'
方式三:双写过渡期
# 过渡期:同时写入 Prometheus 本地和 VictoriaMetrics
# prometheus.yml
remote_write:
- url: "http://victoria-metrics:8428/api/v1/write"
queue_config:
capacity: 10000
# 步骤:
# 1. 配置 Prometheus remote_write 到 VM(开始双写)
# 2. 观察数据一致性,确认无丢失
# 3. 迁移历史数据(vmctl)
# 4. 验证历史数据完整
# 5. 切换 Grafana 数据源到 VM
# 6. 确认稳定后停用 Prometheus remote_write
# 7. 最终用 vmagent 完全替代 Prometheus
性能调优
写入性能优化
1. 调整 remote_write 批量参数
# Prometheus remote_write 调优
remote_write:
- url: "http://victoria-metrics:8428/api/v1/write"
queue_config:
capacity: 25000 # 队列容量(默认 10000)
max_samples_per_send: 5000 # 每批发送样本数(默认 100)
batch_send_deadline: 2s # 批量发送超时(默认 5s)
min_backoff: 500ms # 最小重试间隔(默认 1s)
max_backoff: 10s # 最大重试间隔(默认 30s)
remote_timeout: 30s
2. 调整 VM 内存限制
# vmstorage 内存分配
./victoria-metrics-prod \
-memory.allowedBytes=8GB \
# VM 会使用允许内存的约 60% 作为缓存
# 剩余留给操作系统和其他进程
# 缓存大小调优
-cacheExpireDuration=6h \
-dedup.minScrapeInterval=30s
# 写入优化
-insert.maxQueueDuration=1m \
-insert.maxBlockDuration=5m
3. 控制高基数指标
高基数是监控系统的头号杀手。以下是需要严格控制的标签:
# 检查高基数指标
# 按时间序列数量排序,找出最占资源的指标
topk(20, count by (__name__)({__name__=~".+"}))
# 检查标签基数
topk(20, count by (__name__, job)({__name__=~".+"}))
# 找出标签组合爆炸的指标
topk(10, count by (__name__)({__name__=~"http_request_.*"}))
高基数治理建议:
| 场景 | 问题 | 解决方案 |
|---|---|---|
HTTP 请求带 path 标签 | 每个 URL 路径生成一条时间序列 | 归一化路径,移除 ID 和参数 |
容器带 container_id | 每个容器实例一条序列 | 使用 container_name 替代 |
用户级监控带 user_id | 每个用户一条序列 | 聚合到租户/团队级别 |
异常追踪带 stack_trace | 每个异常堆栈一条序列 | 只保留异常类型和消息 |
查询性能优化
1. 使用 MetricsQL 优化查询
MetricsQL 是 VictoriaMetrics 对 PromQL 的扩展,提供了更多优化函数:
# 标准 PromQL 查询
rate(http_requests_total[5m])
# MetricsQL 优化版 — 使用 range_first / range_last
# 只取窗口起始和结束值,减少计算量
# 适合 counter 类型的大范围查询
rate(http_requests_total[5m] @ end())
# MetricsQL 的 keep_metric_names 修饰符
# 保留原始指标名,便于聚合后识别
sum by (job) (rate(http_requests_total[5m])) keep_metric_names
# MetricsQL 的 lag() 函数
# 处理延迟到达的数据,避免计算偏差
rate(http_requests_total[5m] lag(30s))
2. 降采样查询
对于长期数据的查询,使用降采样减少数据量:
# 原始查询(30 天数据,每 15s 一个点 = 172800 个点)
rate(cpu_usage[30d])
# 使用 MetricsQL 的 downgrade
# 将 30 天数据降采样到 1 小时粒度 = 720 个点
# 大幅减少查询数据量和响应时间
rate(cpu_usage[30d:1h])
# 手动降采样
# 每小时取一个平均值
avg_over_time(rate(cpu_usage[5m])[30d:1h])
3. 查询缓存
# vmselect 启用查询缓存
./vmselect-prod \
-cacheDataPath=/cache \
# 查询结果缓存
-search.cacheSize=2GB \
-search.cacheTTL=5m \
# 索引缓存
-search.indexCacheSize=1GB \
# 过滤缓存
-search.filterCacheSize=1GB
存储优化
# vmstorage 存储优化参数
./vmstorage-prod \
-storageDataPath=/vm-data \
-retentionPeriod=180d \
# 降采样配置
-downsampling.period=30d:5m,180d:1h \
# 含义:30天以上数据降采样到5分钟粒度,180天以上降采样到1小时
# 数据去重
-dedup.minScrapeInterval=30s \
# 当多个 vmagent 采集相同目标时,自动去重
# 索引优化
-index.maxSeriesPerIndexBlock=300000 \
# 内存管理
-memory.allowedBytes=16GB
高可用架构设计
复制与容灾
VictoriaMetrics 集群版支持数据复制,确保单节点故障不丢数据:
# vminsert 配置数据复制
# replicationFactor=2 表示每条数据写入 2 个 vmstorage 节点
./vminsert-prod \
-httpListenAddr=:8480 \
-storageNode=vmstorage-1:8400 \
-storageNode=vmstorage-2:8400 \
-storageNode=vmstorage-3:8400 \
-replicationFactor=2
# 复制架构(replicationFactor=2, 3 个 storage 节点)
写入请求 → vminsert
│
├──→ vmstorage-1 (主) ──→ vmstorage-2 (副本) ✓ 成功
├──→ vmstorage-2 (主) ──→ vmstorage-3 (副本) ✓ 成功
└──→ vmstorage-3 (主) ──→ vmstorage-1 (副本) ✓ 成功
# vmstorage-1 宕机后
# vminsert 自动将数据写入 vmstorage-2 和 vmstorage-3
# 查询时 vmselect 从存活的节点获取数据,无感知
备份与恢复
#!/bin/bash
# VictoriaMetrics 备份脚本
# 1. 创建快照
SNAPSHOT_PATH=$(curl -s -X POST http://localhost:8428/snapshot/create | jq -r '.snapshot')
echo "创建快照: ${SNAPSHOT_PATH}"
# 2. 使用 vmbackup 推送到 S3
./vmbackup-prod \
-storageDataPath=/var/lib/victoria-metrics-data \
-snapshotName="${SNAPSHOT_PATH}" \
-dst=s3://monitoring-backup/vm-snapshots/$(date +%Y%m%d)/
# 3. 验证备份完整性
./vmbackupmanager-prod verify \
-dst=s3://monitoring-backup/vm-snapshots/$(date +%Y%m%d)/
# 4. 清理旧快照(保留最近 7 天)
curl -X POST "http://localhost:8428/snapshot/delete?keep=7"
echo "备份完成"
# 恢复流程
./vmrestore-prod \
-src=s3://monitoring-backup/vm-snapshots/20260711/ \
-dst=/var/lib/victoria-metrics-data/
Grafana 集成
数据源配置
# Grafana 数据源配置(Provisioning)
apiVersion: 1
datasources:
# VictoriaMetrics 作为 Prometheus 数据源
- name: VictoriaMetrics
type: prometheus
access: proxy
url: http://vmselect:8481/select/0/prometheus/
isDefault: true
jsonData:
timeInterval: "15s"
httpMethod: "POST"
# 启用 MetricsQL 扩展
customQueryParameters: "extra_label=cluster=production"
# 如果使用多租户
- name: VictoriaMetrics (tenant-a)
type: prometheus
access: proxy
url: http://vmselect:8481/select/tenant-a/prometheus/
jsonData:
timeInterval: "15s"
推荐的 Dashboard
VictoriaMetrics 官方提供了丰富的 Grafana Dashboard 模板:
# 导入官方 Dashboard(Grafana → Import → ID)
Dashboard ID 说明
────────────────────────────────────
11176 VictoriaMetrics 单节点概览
14289 VictoriaMetrics 集群概览
14592 vmagent 状态概览
14594 vmalert 规则执行概览
14595 vmrestore 备份概览
14596 vmbackup 备份状态
生产环境好的实践
容量规划
根据 VictoriaMetrics 官方文档和社区经验,以下容量规划参考:
| 规模 | 活跃时间序列 | 写入速率 | 单节点配置 | 集群配置 |
|---|---|---|---|---|
| 小型 | <100 万 | <20K samples/s | 4C/8GB/100GB SSD | 不需要 |
| 中型 | 100-500 万 | 20K-100K | 8C/16GB/500GB SSD | 3 storage × 8C/16GB |
| 大型 | 500-2000 万 | 100K-500K | 不推荐 | 3-5 storage × 16C/64GB |
| 超大 | >2000 万 | >500K | 不推荐 | 5-10 storage × 32C/128GB |
存储容量估算公式:
#!/usr/bin/env python3
"""
VictoriaMetrics 存储容量估算工具
基于活跃时间序列数量、保留期和采样间隔进行估算
"""
def estimate_storage(
active_series: int,
retention_days: int,
scrape_interval_sec: int = 15,
avg_label_size: int = 100, # 每条序列的平均标签字节数
):
"""
估算 VictoriaMetrics 所需的磁盘空间
参数:
active_series: 活跃时间序列数量
retention_days: 数据保留天数
scrape_interval_sec: 采集间隔(秒)
avg_label_size: 平均标签字节数
"""
# 每个数据点大小(VM 压缩后约 1-2 字节)
bytes_per_point = 1.5
# 计算总数据点数
points_per_series_per_day = 86400 / scrape_interval_sec
total_points = active_series * points_per_series_per_day * retention_days
# 数据点存储空间
data_storage = total_points * bytes_per_point
# 索引空间(约为数据空间的 20-30%)
index_storage = data_storage * 0.25
# 标签存储空间
label_storage = active_series * avg_label_size * 2 # 压缩后
# 总存储空间
total_storage = data_storage + index_storage + label_storage
# 额外开销( WAL、临时文件等,约 10%)
total_with_overhead = total_storage * 1.1
return {
"active_series": active_series,
"retention_days": retention_days,
"scrape_interval_sec": scrape_interval_sec,
"total_points": int(total_points),
"data_storage_gb": data_storage / 1024**3,
"index_storage_gb": index_storage / 1024**3,
"label_storage_gb": label_storage / 1024**3,
"total_storage_gb": total_with_overhead / 1024**3,
}
# 示例计算
configs = [
("小型", 100_000, 90, 15),
("中型", 1_000_000, 180, 15),
("大型", 5_000_000, 180, 15),
("超大", 20_000_000, 365, 30),
]
print(f"{'规模':<8} {'序列数':>12} {'保留天数':>8} {'存储(GB)':>10} {'存储(TB)':>10}")
print("-" * 55)
for name, series, days, interval in configs:
result = estimate_storage(series, days, interval)
print(f"{name:<8} {series:>12,} {days:>8} {result['total_storage_gb']:>10.1f} {result['total_storage_gb']/1024:>10.2f}")
输出示例:
规模 序列数 保留天数 存储(GB) 存储(TB)
-------------------------------------------------------
小型 100,000 90 1.2 0.00
中型 1,000,000 180 25.6 0.02
大型 5,000,000 180 128.0 0.13
超大 20,000,000 365 768.0 0.80
注意:以上为理论估算值,实际存储消耗受数据特征(标签基数、数据分布等)影响较大,建议以实际测试为准。
监控 VictoriaMetrics 自身
# vmagent 抓取 VictoriaMetrics 自身指标的配置
scrape_configs:
- job_name: "victoria-metrics"
static_configs:
- targets: ["victoria-metrics:8428"]
# VM 在 /metrics 端点暴露自身指标
- job_name: "vmstorage"
static_configs:
- targets: ["vmstorage-1:8482", "vmstorage-2:8482"]
- job_name: "vminsert"
static_configs:
- targets: ["vminsert-1:8480", "vminsert-2:8480"]
- job_name: "vmselect"
static_configs:
- targets: ["vmselect-1:8481", "vmselect-2:8481"]
关键告警规则:
# vmalert 规则 — VictoriaMetrics 自身健康监控
groups:
- name: victoriametrics-alerts
rules:
# vmstorage 磁盘使用率
- alert: VMStorageDiskUsageHigh
expr: |
100 * (1 - vm_data_disk_free_bytes / vm_data_disk_total_bytes) > 85
for: 10m
labels:
severity: warning
annotations:
summary: "VM storage 磁盘使用率超过 85%"
description: "节点 {{ $labels.instance }} 磁盘使用率: {{ $value }}%"
# 写入速率异常
- alert: VMIngestionRateDrop
expr: |
rate(vm_rows_ingested_total[5m]) < 100
for: 5m
labels:
severity: critical
annotations:
summary: "VM 数据写入速率异常下降"
description: "当前写入速率: {{ $value }} rows/s"
# 查询延迟过高
- alert: VMSlowQueries
expr: |
histogram_quantile(0.95,
rate(vm_select_query_duration_seconds_bucket[5m])
) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "VM 查询 P95 延迟超过 10 秒"
description: "P95 延迟: {{ $value }}s"
# 内存使用过高
- alert: VMHighMemoryUsage
expr: |
100 * vm_memory_bytes / vm_memory_allowed_bytes > 90
for: 5m
labels:
severity: critical
annotations:
summary: "VM 内存使用率超过 90%"
description: "内存使用: {{ $value }}%"
# 节点不可达
- alert: VMNodeDown
expr: up{job=~"victoria-metrics|vmstorage|vminsert|vmselect"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "VM 节点不可达"
description: "{{ $labels.instance }} 不可达"
Thanos vs VictoriaMetrics 选型对比
| 维度 | Thanos | VictoriaMetrics |
|---|---|---|
| 架构复杂度 | 高(6+ 组件) | 低(1-3 组件) |
| 外部依赖 | 对象存储 (S3/MinIO) | 无 |
| 数据压缩率 | 中等 (2-3x) | 高 (5-7x) |
| 查询性能 | 中等 | 高 |
| 运维成本 | 高 | 低 |
| 全局查询 | 原生支持 | 原生支持 |
| 降采样 | Compactor 组件 | 内置 |
| 高可用 | Sidecar + Receiver | 集群复制 |
| 生态兼容 | 完全兼容 Prometheus | 完全兼容 + MetricsQL 扩展 |
| 学习曲线 | 陡峭 | 平缓 |
| 适用规模 | 中大型 | 中小型到超大 |
选型建议:
- 选 VictoriaMetrics:希望极简运维、追求高压缩率和查询性能、没有对象存储基础设施、团队规模有限
- 选 Thanos:已有对象存储基础设施、希望利用 S3 做冷数据归档、需要与现有 Prometheus 深度集成、对对象存储生态有经验
- 混合方案:VictoriaMetrics 做热数据存储(近 3 个月),Thanos 做冷数据归档(3 个月以上)到 S3
总结
VictoriaMetrics 作为 Prometheus 长期存储方案,在压缩率、查询性能和运维复杂度方面都有显著优势。以下是选择和落地 VM 的关键要点:
从单节点开始:对于大多数中小规模场景,VM 单节点已经足够强大,单实例可处理 100 万活跃时间序列和每秒 200 万样本写入。无需一开始就上集群版。
vmagent 是采集利器:使用 vmagent 替代 Prometheus 做数据采集,可以获得分片、复制和协议转换能力,同时完全兼容 Prometheus 配置格式。
复制保证可用性:集群版配置
replicationFactor=2即可实现数据冗余,单节点故障不影响读写。配合 vmbackup 做异地备份,实现完整的容灾方案。治理高基数是前提:再好的存储方案也扛不住无限制的标签爆炸。在迁移到 VM 之前,先治理高基数指标,这是监控系统健康的基础。
善用 MetricsQL:MetricsQL 的降采样、延迟处理等扩展函数,可以在不修改采集配置的情况下优化查询性能。
监控监控系统:VictoriaMetrics 自身的健康同样需要监控。磁盘使用率、写入速率、查询延迟和内存使用是四大核心指标。
迁移路径清晰:双写过渡 → 历史数据迁移 → 数据源切换 → 停用旧 Prometheus,每一步都可以验证,风险可控。
参考文档:
- VictoriaMetrics 官方文档 — https://docs.victoriametrics.com/
- VictoriaMetrics GitHub — https://github.com/VictoriaMetrics/VictoriaMetrics
- VictoriaMetrics FAQ — https://docs.victoriametrics.com/FAQ.html
- VictoriaMetrics Operator — https://docs.victoriametrics.com/operator/
参考资料与致谢
本文在撰写过程中参考了以下资料,感谢原作者的贡献:
- VictoriaMetrics Operator 官方文档 — VictoriaMetrics 文档,参考了VictoriaMetrics Operator 官方文档相关内容
- VictoriaMetrics vs Thanos — VictoriaMetrics 文档,参考了VictoriaMetrics vs Thanos相关内容
- 社区选型讨论 — CSDN,参考了社区选型讨论相关内容
- docs.victoriametrics.com — VictoriaMetrics 文档,参考了相关技术内容
- github.com — GitHub 开源社区,参考了VictoriaMetrics相关内容
- docs.victoriametrics.com — VictoriaMetrics 文档,参考了FAQ.html相关内容