资讯动态

VictoriaMetrics单机版部署:接管Prometheus长期存储

发布时间:2026/10/6 16:58:46 来源:尧图企业网站定制
团队监控之前一直用Prometheus单机跑节点一多起来最让人头疼的就是本地存储。默认15天保留期看着够用真到了要翻一个月前的历史数据去定位问题的时候能查到的时间窗口往往就是不够。后来我干脆把VictoriaMetrics用docker-compose架起来做长期存储让Prometheus只负责采集数据全部通过remote write推到VM里。这套方案跑了大半年从搭建、数据接入到备份恢复坑也踩了不少这篇文章就把完整过程记录下来顺便把网上最容易漏掉的那几个细节一并说清楚。写这篇东西之前也顺手查了下社区动态现在很多人管VictoriaMetrics叫“松果时序数据库”实际指的是同一个东西只是它的Logo形象比较深入人心。不管叫松果也好victoria-metrics也罢这份部署经验都适用。1. 为什么我最终选VictoriaMetrics做Prometheus的长期存储先说选型逻辑。网上聊Prometheus长期存储翻来覆去就那几个方案Thanos、Grafana Mimir、InfluxDB、VictoriaMetrics。每个我都过了一遍最后选了VM单机版原因很简单在中小规模监控场景下它把“存储”这件事的复杂度压到了最低。1.1 Prometheus本地TSDB的短板在什么地方Prometheus自带的是本地TSDB数据按2小时的block切分默认保留时间通过--storage.tsdb.retention.time控制一般生产环境给到15天就已经很吃紧。问题不在于它不能存更久而在于本地磁盘成本和查询性能会随数据量直线上升。如果指标基数大Prometheus的内存占用也会跟着爆OOM是常见事故。它更适合做短期热数据的计算和告警而不是长期历史数据的存储库。另一个被很多人忽略的点是Prometheus本地存储不具备跨节点迁移能力。一台机器挂了数据就跟着没了想重建还得从零开始抓。这就是为什么监控规模上来之后普遍都会引入一个独立的时间序列数据库来承接长期数据。1.2 几个常见替代方案的横向对比方案架构复杂度长期存储能力运维成本适合规模Prometheus本地存储低弱默认保留短磁盘成本高低小规模单机VictoriaMetrics单机版低单二进制强压缩率高支持按时间段保留低中小规模Thanos中Sidecar加对象存储强依赖对象存储中中大规模Grafana Mimir高组件多依赖复杂强支持多租户高大规模集群Thanos本身是个好方案但它绕不开对象存储很多团队没有现成的S3或者GCS本地MinIO又是一层运维负担。Mimir是Grafana Labs的亲儿子功能确实完整但组件太多一个告警规则都分好几块服务小团队根本兜不住。InfluxDB走的是InfluxQL和Flux那一套和PromQL生态还需要做一层迁移适配对已经有Prometheus面板和告警规则的用户来说不够丝滑。VictoriaMetrics直接兼容PromQL和remote write协议这意味着Grafana不需要换数据源类型Prometheus也不需要改采集逻辑只要在配置文件里加一段remote_write指向VM就行。它对外暴露的查询接口就是Prometheus风格的团队现有的面板、告警表达式可以直接复用迁移成本几乎为零。1.3 单机版还是集群版VictoriaMetrics有单机版和集群版两种形态。单机版就是一个二进制启动参数极其简单适合当前规模在百万级时间序列以内的场景。集群版则复杂得多有vminsert、vmselect、vmstorage等多个角色通常是在数据量巨大或者需要水平扩展时才需要上。我的建议很直接绝大多数监控场景先上单机版把备份恢复做好比一上来就搭集群靠谱得多。VM还有一个值得一提的特性数据压缩率远高于Prometheus原生存储。同样保留三个月的数据VM占用的磁盘往往只有Prometheus本地存储的三分之一左右。这意味着同样的硬盘容量你可以在VM上保留更长的历史窗口这对事后回溯故障非常有价值。2. docker-compose部署VictoriaMetrics目录、参数和版本选择的实操记录VM的部署方式有很多直接下载二进制裸跑也行在Kubernetes里面用Helm chart部署也可以但对于大多数用docker-compose管理服务的团队来说用compose文件管理VM是最顺手也最容易迁移的。2.1 docker-compose文件长这样我生产环境里用的compose文件做了精简把无关配置全部去掉核心结构如下services: vmetrics: image: victoriametrics/victoria-metrics:v1.102.1 container_name: vmetrics restart: unless-stopped ports: - 8428:8428 command: - -storageDataPath/victoria-metrics-data - -retentionPeriod90d - -memory.allowedPercent40 - -selfScrapeInterval10s volumes: - vm_data:/victoria-metrics-data volumes: vm_data:新版docker compose不需要version字段我这边直接省略了。命令既可以是docker-compose up -d也可以是docker compose up -d看你宿主机装的是v1还是v2插件。2.2 几个关键flag的参数逻辑-storageDataPath指定数据存储目录对应容器内的/victoria-metrics-data。这个路径决定了你的备份工具后续要读哪个目录务必和volume挂载保持一致。-retentionPeriod是数据保留时间。很多人在这里踩坑默认值是1单位是“月”如果配置成6就会保留6个月而不是6天。我建议写明确的全单位字符串比如90d、24w、1y这样后面接手的同事一眼就能看懂。如果你完全不配置VM默认只保留一个月的历史数据。-memory.allowedPercent40是让VM最多使用宿主机总内存的40%。这个参数在容器里尤其重要因为VM是Go程序会主动缓存数据块来加速查询如果不限制百分比它可能吃掉宿主机大半内存。40%在大多数场景下足够如果机器内存只有4G建议再调低到30%并配合后面的容器内存限制一起用。-selfScrapeInterval10s是让VM定期采集自身运行指标。配置这个不是为了好玩而是为了让Grafana能直接展示VM自身的状态包括查询延迟、写入速率、磁盘空间等排查问题的时候非常有用。2.3 数据目录权限named volume和bind mount的区别我强烈建议用named volume而不是bind mount来存放VM数据。原因是VM官方镜像默认不是用root运行当你把宿主机的一个普通目录挂载进去经常会出现权限不足的报错。如果你非要用bind mount比如把数据放到/data/vmetrics那么创建目录之后要手动修改属主mkdir -p /data/vmetrics chown -R 1000:1000 /data/vmetrics这里1000是VM容器内运行用户的UID。如果你不确定实际UID也可以用docker run --rm -it --user root victoriametrics/victoria-metrics临时起一个容器看数据目录归属看完再删掉。相比之下named volume完全绕开了权限管理docker初始化volume的时候会自动处理好省心很多。2.4 镜像tag和版本策略部署VM最稳妥的方式是固定一个明确的小版本号比如我这里写的v1.102.1。不建议用latest因为VM的迭代速度不慢某一天你执行docker-compose pull之后可能就悄悄升级了底层逻辑虽然一般不会有破坏性变更但监控系统这种东西最怕的就是“无声无息地变了”。另外VM官方镜像还有一个victoriametrics/victoria-metrics:latest-cluster之类的集群版和单机版是两套完全不同的命令行入口别在README都没看的情况下混用。单机版就是victoriametrics/victoria-metrics集群版需要分别部署vmstorage、vminsert、vmselect我这里讲的都是单机版。部署完成后简单验证一下服务是否正常curl http://localhost:8428/health curl http://localhost:8428/api/v1/status/buildinfo第一个接口返回200说明HTTP服务起来了第二个接口会打印版本和运行参数方便确认配置生效。3. Prometheus数据接入remote write配置、队列参数与验证VM部署起来之后下一步就是把Prometheus的数据接到VM里。这里用到的协议是Prometheus标准的remote writePrometheus负责抓取目标指标然后通过HTTP推送到VM的写入接口。3.1 prometheus.yml里加一段remote_write在Prometheus的配置文件prometheus.yml中增加如下配置remote_write: - url: http://localhost:8428/api/v1/write queue_config: max_samples_per_send: 1000 capacity: 20000 min_shards: 1 max_shards: 10如果你的Prometheus和VM不在同一台机器上把localhost替换成VM主机的IP。如果两者都在同一个docker compose网络里也可以直接写成服务名比如http://vmetrics:8428/api/v1/write。重点说下queue_config里这些参数的含义。max_samples_per_send是每次HTTP请求发送的最大样本数调大可以减少请求次数但单次body会变大。capacity是队列容量样本数超出后会开始丢弃或降速相当于一个缓冲池。min_shards和max_shards是并行分片数默认情况下Prometheus会根据写入延迟自动在最小和最大分片之间调整。如果发现VM的CPU不高但Prometheus端写入持续积压可以适当把max_shards调大我这边从5调到10之后写入延迟明显低了。3.2 很多人对remote write的误解有一个认知必须纠正配置了remote write之后Prometheus本地存储并不会停止写入而是会“双写”。也就是说Prometheus把抓到的数据同时写在本地TSDB和VM里。它的作用是转发和复制而不是把本地数据搬走。如果你希望Prometheus本地只保留很短的窗口必须同时调低本地retention参数。我这边Prometheus是以启动参数方式控制的--storage.tsdb.retention.time12h这样Prometheus本地只保留12小时的热数据历史数据全部交给VM。不知道这个逻辑的人往往跑了半年之后发现Prometheus宿主机磁盘还是满了以为是VM没有生效其实是因为本地TSDB一直在默默堆积。如果你的指标量很大又不想把低频指标全部传给VM可以使用write_relabel_configs做指标过滤。比如只想保留机器相关和容器相关的核心指标remote_write: - url: http://localhost:8428/api/v1/write write_relabel_configs: - source_labels: [__name__] regex: up|node_.*|container_.* action: keep这个功能很像采集端的relabel只不过它作用于写入VM之前。合理使用能明显降低VM的存储开销和查询压力。3.3 如何确认数据已经进入VM配置完成后重启Prometheus过一两分钟就可以验证数据是否进了VM。最简单粗暴的方法是用VM自带的查询接口curl -G http://localhost:8428/api/v1/query \ --data-urlencode queryup返回结果里如果能看到Prometheus上报的up指标就说明链路已经通了。这里补充一个小技巧VM自带一个Web UI直接访问http://localhost:8428/vmui在浏览器里就可以跑PromQL表达式调试的时候比Grafana还要快推荐直接用。Grafana接入同样简单添加数据源时类型选PrometheusURL填http://VM主机IP:8428保存后会提示连通性正常然后所有面板数据源直接切成这个新的地址即可。仪表盘和告警规则完全不用改因为VM的查询接口兼容PromQL。如果VM服务端配置了-httpAuth.username和-httpAuth.password那Prometheus端的remote_write也要同步加上认证信息remote_write: - url: http://localhost:8428/api/v1/write basic_auth: username: youruser password: yourpassGrafana数据源里面也是在Auth字段里填Basic Auth。这个配置建议在VM暴露到不可信网络时一定要开别裸奔。4. 备份与恢复vmbackup走远端存储快照接口走本地复制备份恢复是时序数据库选型时最容易忽略、真出问题时又最要命的一环。VM官方提供了专门的备份恢复工具分别是vmbackup和vmrestore底层逻辑和存储结构结合得很好既不要求停机也不要求锁库。4.1 先理解一下VM的存储结构VM的数据在storageDataPath下以若干个不可变的part文件组织时间序列数据被分段压缩存储。这些part文件一旦生成就不再修改过一段时间会自动合并成大块。这个“不可变”特性是vmbackup能实现增量备份的基础既然老文件不会变备份工具只需要同步新增的那些part文件即可。理解这一点后你会明白为什么VM官方不推荐直接拿cp -r或rsync去备份正在运行的数据目录。因为内存中还有一部分数据没有完全刷到磁盘直接复制目录大概率会得到一份“缺页”的备份恢复出来丢数据。正确姿势是通过快照接口或者vmbackup来完成一致性备份。4.2 vmbackup做增量备份vmbackup可以本地备份也可以直接写到S3兼容对象存储。这里先用本地目录做示例。假设数据volume名字叫vm_data目标备份目录是宿主机/backup执行命令如下docker run --rm -it \ -v vm_data:/victoria-metrics-data \ -v /backup:/backup \ victoriametrics/vmbackup:v1.102.1 \ -storageDataPath/victoria-metrics-data \ -snapshot.createURLhttp://localhost:8428/api/v1/snapshot \ -dst/backup关键在-snapshot.createURL这个参数。它会让vmbackup先调用VM的快照接口创建一致性快照再基于快照做备份从根源上避免读到半写状态的数据。如果备份目标是S3就不用挂载本地备份目录直接把-dst换成S3地址victoriametrics/vmbackup:v1.102.1 \ -storageDataPath/victoria-metrics-data \ -snapshot.createURLhttp://localhost:8428/api/v1/snapshot \ -dsts3://mybucket/vmetrics-backupvmbackup默认就是增量机制因为part文件不可变每次执行只会上传上次备份之后新增或变化的文件。所以在crontab里每天或者每小时执行一遍同一个命令即可不需要额外写差异逻辑。4.3 vmrestore恢复数据恢复操作同样干净。先把VM服务停掉或者准备一个全新的数据目录然后执行docker run --rm -it \ -v vm_data:/victoria-metrics-data \ -v /backup:/backup \ victoriametrics/vmrestore:v1.102.1 \ -storageDataPath/victoria-metrics-data \ -src/backup这里的-storageDataPath必须是空目录或待恢复目录不能直接指到还在运行的原数据目录上否则恢复数据会和新写入的数据混在一起搞出脏数据。我通常的做法是先把原目录改名比如mv /victoria-metrics-data /victoria-metrics-data.bak再挂一个全新volume跑恢复确认数据完整后把新目录改回来。4.4 不用工具的备用方案快照接口加外部拷贝在某些受限环境里可能不方便跑vmbackup容器那么退而求其次的方案是通过VM自带的快照接口。curl -XPOST http://localhost:8428/api/v1/snapshot响应类似{status:ok,snapshot:20250606120000}此时在数据目录的snapshots子目录下会生成一个以时间戳命名的快照。要备份的时候直接把这整个快照目录拷贝到异地即可cp -a /victoria-metrics-data/snapshots/20250606120000 /backup/vm-snapshot-20250606120000恢复时把快照目录里的所有内容拷贝到一个空的storageDataPath目录然后启动VM。数据就能被正常读取。注意快照目录不能长期保留在数据目录里不管它会持续占用磁盘。确认备份成功后用以下接口清理curl -XDELETE http://localhost:8428/api/v1/snapshot/202506061200004.5 备份策略的实战建议我现在生产的备份策略分两层。本地快速恢复用rsync拷快照目录到另一台机器每天一次保留最近7天快照异地长期保留用vmbackup打到对象存储每小时一次增量保留30天。每月挑一次低峰时段做恢复演练直接在备用机器上启动一个完整VM实例导入备份数据然后查几个关键指标的连续曲线确认数据是真的可用的。要紧不紧的区别就在这里。很多人跑了半年备份结果第一次演练就发现恢复出来数据缺了一大截原因是备份时没走快照或者恢复目标目录没清空。备份恢复一定要演练过才算数这个真不是口号。5. 部署和运行时踩过的几个坑libz.so.1、权限、OOM和retention最后把我在实际部署和运行VM过程中遇到的问题集中过一遍按排查链路讲方便你直接对照。5.1 宿主机报libz.so.1错误不是VM的问题搜索“docker-compose部署VM时序数据库”的时候很多人会遇到这么一条报错docker-compose: error while loading shared libraries: libz.so.1: failed to map segment from shared object先说结论这个错误和VictoriaMetrics容器没有任何关系报错的进程是宿主机上的docker-compose二进制本身。常见原因是宿主机系统里zlib库缺失或版本不对尤其是通过手动下载二进制方式安装docker-compose的环境最容易出现这种动态链接问题。排查链路如下。先确认docker-compose的二进制类型和动态库依赖file $(which docker-compose) ldd $(which docker-compose) | grep libz如果ldd输出里libz.so.1显示not found说明系统缺少zlib1g库。Debian/Ubuntu下直接安装sudo apt update sudo apt install -y zlib1g装完再执行docker-compose version验证。如果问题依旧检查是不是存在多个zlib版本导致链接顺序错误这种情况往往是因为之前手动编译过zlib覆盖了系统库。最省事的办法是放弃老二进制升级到docker compose v2插件用docker compose命令替代docker-compose彻底绕开旧二进制的动态库依赖问题。5.2 容器数据目录权限报错使用bind mount挂载宿主机目录时VM容器内非root用户创建数据文件经常报cannot create directory之类的错误。识别方法很简单看容器日志或者启动后检查数据目录里面是否有文件生成。解决方式我前面已经写过创建目录后chown -R 1000:1000。如果你不想纠结UID就用named volume。我最初图省事用了bind mount结果每次换机器部署都要处理一遍权限后来统一改成named volume几乎没有再碰到这个问题。5.3 容器OOM和memory.allowedPercent配合问题VM是Go写的高性能数据库默认会吃掉大量内存做缓存。如果docker容器不设内存上限VM通过系统调用看到的是整个宿主机的内存就可能出现一个容器把宿主机内存吃满的情况。此时即使-memory.allowedPercent40看起来只有40%那也是基于宿主机总内存算的依然可能很大。建议在compose里配置容器内存上限比如services: vmetrics: mem_limit: 8g同时把-memory.allowedPercent设为合适的值。我的习惯是容器内存上限8G时VM的allowedPercent设60%这样VM最多用约5G留出余量给系统和其他容器。如果观察到victoria-metrics进程莫名被kill大概率就是OOM优先看dmesg确认。5.4 retentionPeriod的单位陷阱这个坑是很多人的噩梦。VM的-retentionPeriod虽然支持1y、6m、30d这样的组合但当你只写一个数字比如-retentionPeriod6它按月份计算代表6个月不是6天。在没有明确单位的情况下VM默认按“月”解释。我曾经见过一个同事把一个测试环境的retentionTime设成2以为最多存2天结果2个月后才想起来清理磁盘那时候已经晚了。我建议所有部署都写成90d、12w、2y这类明确格式宁可多打一个字母也不要留下理解歧义。这套组合从搭建到目前跑了大半年我自己的运维原则很简单VM保持最小容器化Prometheus只当采集器数据长期存储交给VM备份分成快照加对象存储两层每月固定做一次真实恢复演练。个人体会是VictoriaMetrics的日常运维负担确实比想象中低真正磨人的反而不是数据库本身而是网络、权限、版本这些边角问题。如果你正准备把Prometheus的长期存储交给VM照着这套路径走一遍应该能少踩不少我踩过的坑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑