ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Docker Compose部署VictoriaMetrics:Prometheus监控存储与备份恢复实战

Docker Compose部署VictoriaMetrics:Prometheus监控存储与备份恢复实战 1. 部署思路为什么时序数据库要选 VictoriaMetrics1.1 标题场景拆解一套方案搞定监控全链路先把这个标题拆开看它其实覆盖了一套完整的监控数据链路采集端Prometheus→ 存储端VictoriaMetrics→ 运维保障备份恢复。也就是说不只是起一个容器那么简单的部署问题而是要把怎么落地、怎么接入、怎么保证数据安全这一整条线走通。这套方案的典型使用场景非常明确你的服务已经跑了 Prometheus Grafana但 Prometheus 自带的本地 TSDB 存储总在容量、长期留存、查询性能上卡脖子或者你刚接手一套监控系统看到裸奔的 Prometheus 数据目录又没备份方案着急改造。于是引入 VictoriaMetrics 做统一时序存储Prometheus 只负责抓取和告警数据长期落盘在 VM 里Grafana 的查询走 VM 的接口各司其职。我在实战中为什么坚定推荐这套组合因为 Prometheus 本身的 remote write / remote read 协议是开箱即用的只要 VictoriaMetrics 暴露的 HTTP 接口和 Prometheus 的语言兼容那头都不用改。而 VictoriaMetrics 官方就专门提供了对 Prometheus remote write/read 协议的完整支持甚至很多场景下可以直接当 Prometheus 的远端存储用迁移成本极低。相比自建 Thanos Cortex 那套组件矩阵VM 单机版一个二进制搞定对中小团队来说省心太多。1.2 方案选型单机版还是集群版怎么判断标题里写的是docker-compose 启动 VM 时序数据库那第一件事就是分清单机版和集群版。VictoriaMetrics 有两个形态形态组件适用规模部署复杂度单机版vmsingle单个 victoria-metrics 二进制单机百万时间序列以内个人/小团队低一个容器搞定集群版vmclustervmstorage vminsert vmselect海量时间序列、多副本、水平扩展高至少3类组件配合先说结论绝大多数场景先上单机版。别看集群版听起来更正规它引入的复杂度是肉眼可见的——三个组件各自的端口、存储路径、副本配置都要自己维护一旦 docker-compose 编排没写好排查问题的成本是单机版的翻倍。VM 官方自己的说法也很直接单机版单节点可以处理每秒数百万数据点几十万时间序列完全不在话下。对绝大多数业务监控够用了。真正考虑集群版的时候通常是你已经碰到了这几个信号单节点 CPU 常年 80% 以上、磁盘 IO 扛不住、或者明确需要多副本容灾。标题里提到的是 docker-compose 启动说明定位是轻量部署那我的建议就是单机版起步数据目录挂出来备份做好后面真要扩容再迁集群。这篇文章的主体也按单机版来写集群版的备份思路和它一脉相承只是多几个组件的快照协调。2. 用 docker-compose 快速拉起时序数据库2.1 规划目录结构与配置文件动手写 docker-compose.yml 之前先把目录规划这一步做扎实。别小看目录结构我见过很便宜rm -rf 一时爽的事故就是因为容器数据目录随便挂载、没做统一规划最后迁数据的时候手忙脚乱。建议按这个结构来安排/opt/victoria-metrics/ ├── docker-compose.yml ├── data/ # VM 数据目录挂载到容器 ├── backup/ # 本地备份暂存如有 └── prometheus/ └── prometheus.yml # Prometheus 配置可放同一台机器数据目录一定放到宿主机持久化路径上不要放在容器内——docker-compose 的容器重建太频繁了动不动 update 一下如果数据在容器可写层里那就是灾难。VM 镜像里默认的数据目录是/victoria-metrics-data我们把它映射出来这是整套方案的生命线。2.2 单机版 compose 文件详解这是最核心的一个文件。先给你我的生产级配置再逐行解释为什么这么写version: 3.8 services: victoria-metrics: image: victoriametrics/victoria-metrics:v1.93.12 container_name: vmsingle restart: unless-stopped ports: - 8428:8428 volumes: - ./data:/victoria-metrics-data command: - -storageDataPath/victoria-metrics-data - -retentionPeriod30d # 数据保留30天 - -httpListenAddr:8428 - -memory.allowedPercent30 # VM最多使用宿主机30%内存 - -search.maxQueryDuration30s - -search.maxMemoryPerQuery0 ulimits: nofile: 65536 healthcheck: test: [CMD, wget, -qO, -, http://localhost:8428/health] interval: 30s timeout: 5s retries: 3 start_period: 10s几个关键参数逐一说镜像版本。我看到很多人在玩latest标签图一时省事。这个习惯很危险——VM 的版本升级有时会带来存储格式变化或者参数废弃一旦镜像悄悄更新重启容器后起不来或者数据目录不兼容就是半夜被 call 的节奏。生产环境务必固定到具体版本号比如v1.93.12升级的时候有意识地去操作而不是被 latest 绑架。retentionPeriod。数据保留周期这是最影响磁盘占用的参数。单位可以是d天、w周、y年也可以直接写30d。留意它和快照备份的关系——VM 只会清理当前时间点超过保留周期的旧数据这个过程是后台的vmstorage-rem分片机制做的日常不用管。memory.allowedPercent。VM 的内存管理很激进默认会尽量多用内存来缓存热数据提升查询性能。单机版如果跑在 4G 内存的小机器上不限制它会吃满一半以上。设成30意思是允许用到宿主机 30% 的内存。注意这是百分比不是绝对数值更精确的控制可以改用-memory.allowedBytes2GB。search.maxQueryDuration。直接限制单条查询的最大执行时间默认 5s 对复杂聚合确实不够但在大面板上我建议调到 30s 就够了。太长会让并发查询把 CPU 打满拖垮整个实例。然后是ulimits里把文件描述符开到 65536。这个在很多部署文档里被忽略了——当时间序列数量大、查询并发上来时VM 要同时打开大量数据文件默认 1024 的 ulimit 会导致报too many open files到时候会看到查询突然报错。提前设好省得后面排查。健康检查为什么要单独配因为 docker-compose 默认是不管容器内部服务死没死的。VM 进程起了但内部 HTTP 服务异常或者端口没起来容器还是显示 running编排系统不会感知。加上 healthcheck 后你可以配合后续的 prometheus 抓取或者容器编排做自动恢复这在自动化运维里是基本素养。2.3 启动、验证与内存调优配置写好后启动三板斧docker compose up -d docker compose logs -f victoria-metrics curl -s http://localhost:8428/healthdocker compose logs看启动日志正常会出现类似VictoriaMetrics is ready的字样。然后 curl 一下/health接口返回OK就是真的起来了。这一步是最快的健康验证比盯着docker ps强得多。再检查一下测试接口确认能写入和查询curl -X POST http://localhost:8428/api/v1/write -d test_metric{labelcheck} 100 curl http://localhost:8428/api/v1/query --data-urlencode querytest_metric这两条命令能通说明写入链路和查询链路都没问题。写测试数据的时候注意VM 对没有时间戳的数据会默认带上当前时间所以查回来能看到值这条链路就算验证过了。内存这块再补充一句观察曲线的斜率比观察绝对峰值更重要。VM 的内存使用和活跃时间序列数量强相关如果内存持续上涨、不回落就要怀疑是不是有大量不规律的唯一标签组合高基数问题在写入而非简单调大内存能解决。通过内置的/vmui页面浏览器访问http://localhost:8428/vmui可以直接看时间序列数量、查询耗时等指标很直观比命令行快。3. Prometheus 数据接入配置3.1 remote_write 配置把 Prometheus 的数据双写到 VM装好 VM 之后第二步就是把 Prometheus 的数据接进来。这里有一个设计上的取舍你是想全部数据都写入 VM还是只把长期保留的数据写入 VM我的建议是Prometheus 本地保留短周期如最近6小时~24小时同时通过 remote_write 把全量数据写入 VM查询主要走 VM。这样做的理由是Prometheus 的本地存储很适合做最近数据的快速查询和告警恢复判断而 VM 主要负责长期存储和批量分析两边各取所长。在 Prometheus 的配置文件prometheus.yml里增加这一段remote_write: - url: http://victoria-metrics:8428/api/v1/write queue_config: max_samples_per_send: 5000 capacity: 100000 min_shards: 2 max_shards: 20注意这里的url是 VictoriaMetrics 的写入接口路径/api/v1/write这是它兼容 Prometheus 协议的地方。victoria-metrics是 docker-compose 网络内的服务名如果你在同一 compose 网络里直接用服务名解析即可如果分开部署则用宿主机的 IP 或域名。队列参数为什么要调我推演一下这个逻辑capacity是每个分片内存队列的容量max_samples_per_send是每次批处理发送的最大样本数。默认配置说实话也能跑但在高写入下有几点体验不好——队列容易积压、分片数量不够导致吞吐上不去。调成max_samples_per_send: 5000是因为 VM 官方单次批量解析 5000 行是性价比很好的平衡点吞吐高、内存开销可控。max_shards: 20让 Prometheus 可以在写入压力大时自动扩容分片类似汽车自动挡的换挡逻辑而不是死板地用一个分片慢慢写。3.2 remote_read 配置Grafana 查询走 VM 接口如果只配了 write 没配 read那 Prometheus 本地查询还是走它自己的 TSDBGrafana 数据源连的也是 Prometheus 的话你看到的还是短周期数据。要做长期查询就在 Prometheus 配置里加上 remote_readremote_read: - url: http://victoria-metrics:8428/api/v1/read read_recent: true这里有个小坑值得展开说一下read_recent这个参数。默认情况下Prometheus 的 remote_read 优先查本地存储本地没有的数据才去远端查这样能保证查询性能和一致性。但当你明确想用 VM 做主查询源时——比如 Grafana 面板时间范围远超 Prometheus 本地保留周期——read_recent: true让 Prometheus 直接读远端数据不走本地缓存判断。我实际部署时如果 Grafana 数据源配的是 Prometheus 而 Prometheus 又只留了 24 小时数据不加read_recent: true就会出现选了大时间范围却拉不到数据的诡异现象。加上它之后查询全走 VM问题消失。但注意如果你的Grafana 数据源直接配的 VictoriaMetrics那remote_read这段是不需要的。Grafana 原生支持 VictoriaMetrics 数据源插件直接填 http 地址即可。两条路线我都跑过结论是能用 VM 数据源插件就直接用插件性能和功能更完整如果运营面板已经统一配置了 Prometheus 数据源就用 remote_read 转发。3.3 验证数据是否真正写入配置完 remote_write/read 后别急着看面板先在 VM 侧确认有没有数据# 在 VM 上查最近5分钟是否有数据 curl http://localhost:8428/api/v1/query --data-urlencode queryup # 或者查特定指标 curl http://localhost:8428/api/v1/query_range \ --data-urlencode queryup \ --data-urlencode start1671000000 \ --data-urlencode end1671000300 \ --data-urlencode step30这里有两条验证链路一条是 Prometheus 侧看 remote write 队列有没有积压/api/v1/runtimeinfo或 metrics 里的prometheus_remote_storage_queue_highest_sent_timestamp_seconds和prometheus_remote_storage_pending_samples如果 pending 一直涨说明写入跟不上另一条是 VM 侧看写入的 api 是否正确返回 204。更直接的方式是到 VM 的http://localhost:8428/vmui页面上输入{__name__~.*}能查到指标列表说明数据已经入到 VM 存储了。我踩过的一个坑是Prometheus 的 remote_write 里写的是http://localhost:8428/api/v1/write而 Prometheus 容器和 VM 容器不在同一个网络命名空间导致 curl 在宿主机通、但 Prometheus 容器内部访问不到localhost。解决方式就是把 URL 改成 docker-compose 网络内互通的服务名或宿主机 IP例如http://victoria-metrics:8428/api/v1/write。这个问题看起来基础但出问题时很容易绕进去——因为你宿主机 curl 是通的容器内不通你甚至会怀疑是不是 Prometheus 配置没生效。4. 备份恢复VM 的快照与备份工具4.1 备份原理为什么 VM 不直接打包数据目录很多人会想备份数据把./data目录 tar 起来不就行了说真的这个想法第一眼看没毛病但在线备份时会踩大坑。VM 的存储引擎在运行时会持续写数据分片partition和内存中的相关索引直接tar -czf一个正在被写入的数据目录大概率得到的是一个在某一瞬间被撕裂的镜像——文件夹结构不完整、部分数据文件正在写入却被打包成半个文件、数据目录内部的临时文件和正在进行 flush 的分区处于中间态。这样的备份拿去恢复轻则丢数据重则恢复出来的 VM 起不来报各种损坏错误。所以 VM 官方给出的推荐路径是先用快照接口生成一致的备份起点再用 vmbackup 工具备份快照目录。整个备份过程是在线的不需要停止 VM 服务非常关键。VM 的接口是# 创建快照 curl -X POST http://localhost:8428/snapshot/create # 返回内容为 {status:ok,snapshot:20240201_1234567890}创建一个快照后在数据目录下会生成一个snapshots/20240201_1234567890子目录。逐一说明这个过程VM 在接到快照请求时会做两件事——强制把内存中的数据进行落盘同时记录一个数据一致性位置之后新写入的数据不会影响这个快照点的完整性。所以快照目录就是某一时刻数据库数据的一致副本此时你再对它做文件级备份就是安全的。4.2 vmbackup 实战备份到对象存储或 NFS打快照只是第一步快照还在 VM 本机的数据目录里如果这台机器磁盘坏了快照一样灰飞烟灭。所以要用vmbackup把快照传到异地存储。官方提供的镜像是victoriametrics/vmbackupdocker-compose 可以直接跑一次性任务docker run --rm \ -v /opt/victoria-metrics/data:/data \ -e BACKUP_DIR/backups \ victoriametrics/vmbackup:v1.93.12 \ -storageDataPath/data \ -snapshotName20240201_1234567890 \ -dstgs://my-bucket/vm-backupdst目标支持的对象存储有 GCS、S3、Azure Blob、MinIO 等甚至本地目录fs://也行。对你来说最常见的是 S3 兼容存储——包括腾讯云 COS、阿里云 OSS、MinIO 都能用 S3 协议对接。参数里加一组 access key 和环境变量即可。还有一个非常实用的参数-origin。它的作用是做增量备份——origin指向上一次完整备份的路径vmbackup 只把快照相对于 origin 的变化部分上传。监控数据的备份其实每天变化量不大但全备的话数据量会越滚越大增量备份能大幅节省存储成本和时间。建议初始做一次全备之后每天跑的备份命令带上-origings://my-bucket/vm-backup-YYYYMMDD可以精确控制。备份策略和频率方面我操作时的建议是每天一个增量备份每周一个全量备份全量备份保留4周。如果是比较重要的业务监控可以再叠加一次每月全备保留更长周期。备份这件事永远是宁可多备不可少备但也不建议无脑堆——因为恢复时要能找得到目标时间点堆太多反而干扰。4.3 快照管理和生命周期快照目录会一直留在 VM 的数据目录里如果不清理它占用的磁盘空间会不断累积。官方提供了删除接口# 删除单个快照 curl -X POST http://localhost:8428/snapshot/delete \ --data-urlencode snapshot20240201_1234567890 # 删除全部快照 curl -X POST http://localhost:8428/snapshot/delete_all我建议在 vmbackup 备份成功后立即删掉对应的本地快照没必要留着。但注意一个时序问题先备份再删除快照这个顺序不能反。我见过有人图省事写了个 cron 里先 delete_all 再跑 backup结果备份了个寂寞恢复点全部丢失。这就是一个很明显的工作流顺序问题。另外提醒一下快照删除对磁盘空间的释放不是瞬时的。VM 内部的vmstorage后台任务会逐步整理分区并合并小文件磁盘空间真正释放可能需要一些时间。如果你删完快照发现磁盘使用率还是很高别慌观察一段时间它会逐渐把可回收的分区合并后释放。这个和大多数基于 LSM 树的存储引擎行为一致。4.4 vmrestore 恢复一次完整的演练恢复就是备份的逆过程。假设你备份在 GCS 的gs://my-bucket/vm-backup目录下现在 VM 数据目录全丢了要恢复到新机器# 1. 先停掉 VM 容器 docker compose stop victoria-metrics # 2. 恢复到一个全新的数据目录 docker run --rm \ -v /opt/victoria-metrics/data_restore:/data \ victoriametrics/vmrestore:v1.93.12 \ -srcgs://my-bucket/vm-backup \ -storageDataPath/data # 3. 把恢复出来的数据目录替换原路径 mv /opt/victoria-metrics/data_restore /opt/victoria-metrics/data # 4. 重新启动 VM docker compose up -d步骤 2 里vmrestore会自动从远端存储拉取备份数据并解压归档。有个细节如果你用增量备份-src也要指向增量备份的那个路径vmrestore 会自动关联 previous 的增量链式恢复不需要手动合并——当然前提是你备份时的-origin链式关系是连续的。一旦断链老实的做法是回到最近一次全备恢复再补打后续增量但操作复杂度会稍高一些。恢复完成后的第一件事不是看面板而是先验证数据完整性# 查一个已知指标的最近数据 curl http://localhost:8428/api/v1/query --data-urlencode queryup # 查最后一个时间点确认数据没丢到最近 curl http://localhost:8428/api/v1/query --data-urlencode querylast_over_time(up[24h])我强烈建议在部署完这套方案后在测试环境做一次完整的恢复演练。不用等出事故才操作演练一次大概 30 分钟但能让你对命令参数、恢复顺序、Log 输出这些细节烂熟于心。等真出事故的时候你就是那个还能冷静执行恢复预案的救场人而不是抽象地在文档里临时查命令。5. 常见问题与排查技巧实录5.1 docker-compose 启动失败libz.so.1 错误网上热词里反复出现docker-compose: error while loading shared libraries: libz.so.1: failed to map segment from shared object这个报错。这个场景最近集中爆发的原因多半是 docker-compose v2 版本的二进制依赖 glibc 版本和宿主机的 glibc 不匹配或者老机器的/lib路径问题。先把结论说在前面优先升级 Docker Engine 和 docker-compose 插件本身不要在一个老旧的 compose 二进制上死磕。因为新版 Docker 已经把 compose 作为 docker 插件内置了直接docker compose带空格调用不需要单独维护docker-compose二进制。我用docker compose替代旧命令后这种动态库错误几乎绝迹。如果你暂时没法升级还是必须用老版 docker-compose可以临时用环境变量绕过但我不推荐在生产环境这么裸奔# 临时切库路径仅排查用 LD_LIBRARY_PATH/usr/lib/x86_64-linux-gnu docker-compose up -d这个 libz 问题的根源是二进制预期链接的 zlib 库版本和系统实际存在的不一致。Linux 下解决方案其实就是换兼容版本、升级 Docker 或重装 zlib。排查时有几条路径ldd $(which docker-compose)看它动态依赖哪些库哪个标了not found就去装对应的库。治标先治本最终还是要升级环境。5.2 VM 容器一直重启数据目录权限问题有一次我把 VM 的数据目录从一个 NFS 挂载盘迁到本地容器一直Restarting日志里只看到权限报错cannot create directory /victoria-metrics-data: permission denied再仔细看发现 NFS 挂载时用的 uid/gid 和宿主机不一致VM 镜像里默认以非 root 用户运行没有目标目录的写权限。解决方式很简单mkdir -p /opt/victoria-metrics/data chown -R 1000:1000 /opt/victoria-metrics/dataVM 镜像官方使用 uid 1000 作为默认用户直接chown 1000:1000就能让容器正常写入。这个细节容易忽略尤其是从 Windows 挂载盘迁过来、以及用 NFS 存储的时候权限经常会出问题。排查顺序数据目录权限 磁盘剩余空间 端口占用。5.3 Prometheus 写入成功但 VM 查询无数据我遇到过一种很隐蔽的情况Prometheus 的 remote_write 显示成功了没有 pending 积压但 VM 上查询不到数据。当年排查了半个多小时最后发现是时间范围不对——有些查询面板默认查最近5分钟或15分钟而我测试写入的数据恰好是 2 个小时前的。这个问题看起来笨但它暴露了一个关键点VM 的查询默认不带时间过滤时是按当前时间往前推的这很容易让人误判没有数据。正确排查思路是用 VMUI 的query页面直接输入一条不带时间的查询比如sum(up)然后看返回结果。如果返回值非空说明数据已经入库面板查不到是时间范围的问题如果返回空则要看 Prometheus 的写入链路。另一个排查点Prometheus 里某些指标是带 labels 的而查询时如果用up{jobfoo}这种精确匹配VM 也遵循同样的 PromQL 语义。如果 label 大小写写错也会查不到。用 VMUI 的自动补全功能把 label 从列表里直接点选出来能避免手写 label 拼写错误这种低级问题。5.4 查询变慢内存、磁盘、高基数最后说说查询性能。VictoriaMetrics 的查询优化总体做得不错但如果你的监控面板越来越卡优先怀疑以下几点第一查询范围过大。比如up这类高基数指标拉 30 天的曲线所耗内存会非常夸张。我见过有同事直接大范围 * 全量指标一起查结果 OOM把整台机器打挂了。解法是尽量缩小时间范围或者用downsample接口让 VM 自动降采样比如/api/v1/query_range支持step参数Grafana 也会自动调整点距但仍建议你在面板上限制时间跨度。第二磁盘 IO 瓶颈。VM 读数据依赖磁盘如果查历史数据特别慢看下iostat或vmstat如果磁盘利用率长时间接近 100%要么换 SSD、要么考虑把查询频繁的分区做缓存。VM 自带-storage.cacheSize之类的参数可以适当加大查询缓存内存但别贪——内存也被查询本身占用。第三高基数问题。时间序列数量过大对存储和查询都有影响。VMUI 页面里可以看 cardinality stats如果发现有某个 label 有几万个不同值典型的是pod、instance、user_id这类就要认真权衡是否真的需要这个维度。高基数不是说绝对不能存而是会让查询聚合变慢、存储膨胀。实际解决办法一般是减少不必要的 label或者只在需要时用单独的指标跟踪不要在同一个指标里打满各种唯一维度。6. 踩过几次坑之后的运维心得这套组合拳打下来我在实际维护中最重要的体会是时序数据库的运维核心不是部署起来而是数据和查询的长期健康。docker-compose 把 VictoriaMetrics 拉起来Prometheus 数据接进来备份策略配好这些只是第一步。真正拉开差距的是接下来的持续关注——磁盘空间是否悄悄涨满、remote_write 队列是否积压、高基数指标是否在某次发布后暴涨、备份任务是否真的按时成功了。我给自己定了一套日常巡检习惯分享给你参考每天花 30 秒看 VM 的磁盘使用曲线和远程存储队列积压每周看一次备份任务日志确认快照创建、备份上传、快照删除三步都完成了每月用测试数据做一次恢复验证确保 vmrestore 的链路和权限都没出问题。这30秒、一周、一个月的节奏性价比极高。另外一个小技巧VMU I 页面里的/metrics是可以被 Prometheus 自身抓取的把victoria-metrics的指标也纳入监控体系这样 VM 自身健康状态也能被观测。这算是吃自己的狗粮但如果连时序数据库的运维指标都没接入监控出了问题往往是最措手不及的。我已经踩过这些坑你可以直接抄作业了。
返回列表