vm3机2副本架构

VictoriaMetrics 单机房 3 节点 RF=2 部署与单机故障恢复 Runbook

1. 结论

如果你只有 3 台机器,并且每台机器启动 1 个 vmstorage,那么 -replicationFactor=2 通常比 -replicationFactor=3 更合理

原因是 VictoriaMetrics 官方文档给出的约束是:

1
2
要在 N-1 个 vmstorage 不可用时,仍维持新写入的 N 副本,
集群至少需要 2*N-1 个 vmstorage。

所以:

副本数所需最小 vmstorage 数3 台机器是否合适说明
RF=23合适坏 1 台后,剩余 2 台仍可维持新写入 2 副本。
RF=35不合适正常态可以三副本,但坏 1 台后只剩 2 台,无法继续三副本写入。

在你的规模下,推荐:

1
2
3
4
5
6
host-a: 1 个 vmstorage, /data/vmstorage = 3 块盘组合出的数据卷
host-b: 1 个 vmstorage, /data/vmstorage = 3 块盘组合出的数据卷
host-c: 1 个 vmstorage, /data/vmstorage = 3 块盘组合出的数据卷

vminsert -replicationFactor=2 -> host-a, host-b, host-c
vmselect -replicationFactor=2 -> host-a, host-b, host-c

2. 磁盘与进程模型

每台机器 3 块盘,通常只启动 1 个 vmstorage

三块盘先在 OS 层组合成一个挂载点:

  • RAID0/LVM stripe:容量和性能最好;任意一块盘坏了,就按整台机器故障处理。
  • RAID5/RAIDZ1:能扛本机单盘故障,但写入和重建成本更高。
  • 云盘/分布式盘:如果底层已经有冗余,可以直接挂载给 vmstorage

vmstorage 只配置一个数据目录:

1
2
3
4
5
6
vmstorage \
  -storageDataPath=/data/vmstorage \
  -retentionPeriod=180d \
  -httpListenAddr=:8482 \
  -vminsertAddr=:8400 \
  -vmselectAddr=:8401

不要把 3 块盘拆成 3 个 vmstorage。VictoriaMetrics 的副本是按 vmstorage 节点做的,不感知哪些节点在同一台物理机上;每盘一个进程会让机器故障域和副本故障域错位。

3. 正常部署

3.1 vminsert

至少部署 2 个 vminsert,前面挂 LB 或 vmauth

1
2
3
4
5
6
vminsert \
  -httpListenAddr=:8480 \
  -replicationFactor=2 \
  -storageNode=host-a:8400 \
  -storageNode=host-b:8400 \
  -storageNode=host-c:8400

remote write 入口:

1
http://<vminsert-lb>:8480/insert/0/prometheus/api/v1/write

3.2 vmselect

至少部署 2 个 vmselect,前面挂 LB 或 vmauth

1
2
3
4
5
6
7
vmselect \
  -httpListenAddr=:8481 \
  -replicationFactor=2 \
  -dedup.minScrapeInterval=1ms \
  -storageNode=host-a:8401 \
  -storageNode=host-b:8401 \
  -storageNode=host-c:8401

如果有两个 vmagent 或两套 Prometheus 同时采同一批 target,-dedup.minScrapeInterval 建议设成实际 scrape_interval,例如 15s

3.3 vmagent

写同一个 VictoriaMetrics Cluster 时,vmagent 只需要写一个 vminsert 入口;集群内部由 vminsert 负责复制:

1
2
3
4
5
vmagent \
  -promscrape.config=/etc/vmagent/prometheus.yml \
  -remoteWrite.url=http://<vminsert-lb>:8480/insert/0/prometheus/api/v1/write \
  -remoteWrite.tmpDataPath=/data/vmagent-queue \
  -remoteWrite.maxDiskUsagePerURL=500Gi

vmagent 的本地队列用于 vminsert 入口不可用时缓存数据,恢复后补发。

4. RF=2 的故障表现

4.1 坏 1 台机器

假设 host-b 故障:

  • 历史数据仍可查,因为 RF=2 下每条样本有 2 份,另一份在 host-ahost-c
  • 新写入仍可维持 2 副本,因为剩余 host-ahost-c 正好是 2 个可用 vmstorage
  • vmselect -replicationFactor=2 可以避免单个 storage 不可用时把结果标记为 partial。

这正好符合官方 2*N-1 规则:RF=2 需要至少 3 个 vmstorage

4.2 坏 2 台机器

RF=2 不能承诺同时坏 2 台仍完整可用。此时有些数据可能完全不可查或只剩单副本。

所以 RF=2 的目标是:

1
容忍 1 台机器故障,并在故障期间继续维持 2 副本写入。

不是:

1
容忍 2 台机器同时故障。

5. 备份策略

VictoriaMetrics Cluster 备份需要在每个 vmstorage 节点上分别运行 vmbackup。这个架构有 3 个 vmstorage,所以是 3 份备份。

1
2
3
s3://vm-backup/prod/vmstorage-a/latest
s3://vm-backup/prod/vmstorage-b/latest
s3://vm-backup/prod/vmstorage-c/latest

示例:

1
2
3
4
vmbackup \
  -storageDataPath=/data/vmstorage \
  -snapshot.createURL=http://host-b:8482/snapshot/create \
  -dst=s3://vm-backup/prod/vmstorage-b/latest

建议:

  • 每小时增量备份到 latest
  • 每天从 latest 做服务端 copy,形成日期保留点。
  • 每月至少做一次抽样 vmrestore 演练。
  • 监控 3 个备份任务的最近成功时间和耗时。

6. 单机永久故障后的扩容恢复流程

以下假设 host-b 永久故障,新增 host-d 接替它。

6.1 故障确认

确认:

  • host-b:8400host-b:8401host-b:8482 不可达。
  • vminsert 仍能写入 host-ahost-c
  • vmselect 查询没有非预期 partial。
  • host-ahost-c 资源水位正常。

此时系统处于降级状态:仍可维持 RF=2 写入,但没有额外故障余量。应尽快补回第三台机器。

6.2 新机器准备

新增 host-d

  • 规格不低于 host-b
  • 3 块盘按原方案组合成 /data/vmstorage
  • 文件系统、mount 参数、目录权限保持一致。
  • 安装同版本 VictoriaMetrics。
  • 配置 systemd、ulimit、监控采集、日志、对象存储凭证。

6.3 从备份恢复故障节点数据

host-d 上恢复 host-b 的最近备份:

1
2
3
vmrestore \
  -src=s3://vm-backup/prod/vmstorage-b/latest \
  -storageDataPath=/data/vmstorage

注意:

  • vmrestore 要在 vmstorage 停止时执行。
  • -storageDataPath 必须指向新机器的正确数据目录。
  • 备份时间点之前的数据会恢复出原 host-b 的那一份副本。
  • 备份时间点之后到 host-b 故障前的数据,如果原副本组合包含 host-b,那么现在只剩另一份在 host-ahost-c
  • host-b 故障期间的新写入会落到 host-ahost-c 两份,不依赖 host-b

6.4 启动新 vmstorage

1
2
systemctl start vmstorage
curl http://host-d:8482/metrics

6.5 替换 vminsert/vmselect 配置

host-b 替换成 host-d,滚动重启 vminsert

1
2
3
4
5
6
vminsert \
  -httpListenAddr=:8480 \
  -replicationFactor=2 \
  -storageNode=host-a:8400 \
  -storageNode=host-d:8400 \
  -storageNode=host-c:8400

滚动重启 vmselect

1
2
3
4
5
6
7
vmselect \
  -httpListenAddr=:8481 \
  -replicationFactor=2 \
  -dedup.minScrapeInterval=1ms \
  -storageNode=host-a:8401 \
  -storageNode=host-d:8401 \
  -storageNode=host-c:8401

如果使用稳定 DNS,例如 vmstorage-b.example,也可以把 DNS 指向 host-d,保持配置不变。

6.6 是否需要补齐备份缺口

VictoriaMetrics 不会因为新 vmstorage 加入就自动把历史数据重平衡到新节点。

如果你能接受“备份点之后到故障前,部分数据只有 1 份副本”,可以不做额外回灌,因为查询仍然可用。

如果你要求恢复严格 RF=2,需要补齐缺口窗口:

1
2
缺口开始 = vmstorage-b 最近一次成功备份时间
缺口结束 = host-b 故障时间

可选做法是从健康查询入口导出该窗口数据,再导入集群入口:

1
2
3
4
5
curl "http://<vmselect-lb>:8481/select/0/prometheus/api/v1/export/native?match[]={__name__!=\"\"}&start=<start>&end=<end>" \
  -o vm-gap.native

curl -X POST "http://<vminsert-lb>:8480/insert/0/prometheus/api/v1/import/native" \
  --data-binary @vm-gap.native

这会产生重复写入,查询侧依赖 dedup 去重。建议只对关键 tenant、关键指标或较短窗口执行。

6.7 恢复后立即备份

1
2
3
4
vmbackup \
  -storageDataPath=/data/vmstorage \
  -snapshot.createURL=http://host-d:8482/snapshot/create \
  -dst=s3://vm-backup/prod/vmstorage-b/latest

7. 监控与告警

必须告警:

  • 任意 vmstorage 不可达:vm_rpc_vmstorage_is_reachable == 0
  • 任意 vmstorage 只读:vm_storage_is_read_only == 1
  • vmagent remote write 积压持续增长:vmagent_remotewrite_pending_data_bytes
  • vmagent 丢弃数据:rate(vmagent_remotewrite_packets_dropped_total[5m]) > 0
  • vmbackup 失败或超时。
  • vmstorage 磁盘剩余空间低于 20%。
  • 查询响应出现非预期 partial。

建议面板:

  • 每个 vmstorage 的写入速率、查询速率、CPU、内存、IO wait、磁盘延迟。
  • 每台机器 /data/vmstorage 使用率。
  • vminsert 到各 storage node 的错误率。
  • vmagent pending bytes 和 dropped packets。
  • 每个 vmbackup 最近成功时间和耗时。

8. 最终建议

你的三台机器场景,我建议用:

1
2
3
4
5
6
3 台机器
3 个 vmstorage
每台机器 3 块盘合成 1 个 /data/vmstorage
vminsert -replicationFactor=2
vmselect -replicationFactor=2
每个 vmstorage 单独 vmbackup

这个方案比 RF=3 更均衡:

  • 正常态有 2 副本。
  • 单机故障时仍能查询完整历史数据。
  • 单机故障期间仍能对新写入维持 2 副本。
  • 存储、CPU、网络开销低于 RF=3。
  • 扩容替换时只需要恢复故障节点那一份备份,必要时补齐备份缺口窗口。
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计