HelloCoder HelloCoder
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
首页
《Java小白求职之路》
《小白学Java》
计算机毕设
  • 一些免费计算机资源
  • 脚手架工具
  • 《从0到1学习Java多线程》
  • 《从0到1搭建服务器》
  • 《可观测和监控》
  • 《k8s学习心得》
随笔
关于作者
  • 《从0到1学习Java多线程》

  • 《从0到1搭建服务器》

  • 源码学习

  • 可观测和监控

    • 可观测是什么
    • 指标
    • 链路
    • 日志
    • Zabbix vs Prometheus
    • 基于Micrometer的Prometheus指标生成
    • OpenTelemetry
    • Opentelemetry Collector
    • Opentelemetry尾采样
    • 基于Opentelemetry的filelog插件收集日志
    • Python接入Opentelemetry
    • 基于javaagent探针自动埋点
    • 可观测系统在Flyme落地
    • javaagent的类加载器
    • prometheus指标脱坑
    • 中间件标准化落地
    • 为什么选择Clickhouse而不是ElasticSearch?
    • 使用vm-agent替代prometheus
    • javaagent实现
    • 跨线程传递Context
  • 玩转IDEA

  • AI学习

  • 03-RPC

  • 05-《Java日志框架》

  • k8s

  • 专栏
  • 可观测和监控
#vm-agent #prometheus #使用 #替代
HaC
2026-07-01
目录

使用vm-agent替代prometheus

在云原生监控领域,Prometheus 是老牌的行业标准,而 vm-agent(VictoriaMetrics Agent)则是后起之秀 VictoriaMetrics 生态中的一个轻量级组件。

简单来说:Prometheus 是一个“全能型监控系统”(能刮取、能存储、能查询);而 vm-agent 则是一个“纯粹的指标搬运工”(只负责刮取和发送,不负责本地持久化存储和查询)。

# vm-agent 与 Prometheus 的核心区别

维度 Prometheus vm-agent
定位 完整的监控与时序数据库系统 轻量级的指标采集代理(Agent)
本地存储 有(自带高性能 TSDB,重度依赖磁盘 I/O) 无(仅有临时磁盘 Buffer 用于断网容灾)
资源消耗 较高。随着采集指标量增加,内存和 CPU 消耗会大幅上升。 极低。内存占用通常只有 Prometheus 的几分之一,对 CPU 非常友好。
查询功能 支持(提供原生的 PromQL 查询接口) 不支持(它只管发,不读数据,没有查询接口)
报警计算 支持(本地配置并计算 rule) 不支持(需要依赖远端存储或 vm-alert 来计算)
集群与扩展性 原生不支持分片集群,需要靠 Thanos/Cortex 等外挂方案或联邦模式。 天生支持分布式部署。可以通过多个 vm-agent 配合 hash_mod 实现轻松横向扩展。

# 区别一:集群

在原生的 Prometheus 官方架构哲学里,所谓的“集群部署”,本质上就是多活(Multi-HA)的高可用冗余,它根本不具备任何“分布式分片(Sharding)”和横向扩展性能的能力。

当你为了高可用,在同一个 K8s 集群里部署了两个完全一模一样的 Prometheus 实例(Replica A 和 Replica B)时,它们的工作和去重工作流是这样的:

阶段 Prometheus Replica A (实例 A) Prometheus Replica B (实例 B) 远端分布式存储(如 Thanos / VM)
1. 抓取 (Scrape) 拿着相同的配置,去拉取 Target 1 的指标。 同时拿着相同的配置,去拉取 Target 1 的指标。 (此时毫不知情)
2. 发送 (Push) 通过 remote_write 把带有时戳、标签和 replica=A 的数据发往远端。 同时通过 remote_write 把带有时戳、标签和 replica=B 的数据发往远端。 远端存储同时收到了两份内容完全一样、但唯一标识(Replica 标签)不同的数据流。
3. 存储与去重 (完成任务,继续拉取) (完成任务,继续拉取) 核心点:远端存储(如 Thanos-Receive 或 VictoriaMetrics)在落盘或查询时,根据配置的 deduplication.replica-label=replica,强行把 B 的数据丢弃掉,只留 A 的数据。

解决方案:

# 方案 1:使用 Prometheus Operator 的自研 Hash 分片

如果你必须用 Prometheus,官方的 Prometheus Operator 引入了基于 Hashmod 的分片机制。

  • 工作模式:你在配置文件里声明 shards: 3。
  • 底层原理:Operator 会启动 3 个 Prometheus 实例。实例 1 只抓取 Hash(Pod_IP) % 3 == 0 的 Pod,实例 2 抓取 % 3 == 1 的 Pod。
  • 结果:这才是真正的提高性能(横向扩展),每个 Prometheus 实例只承担1/3 的内存和 CPU 压力。

# 方案 2:完美的终极解法 —— vmagent 自带分布式集群分片

这也是为什么你之前测试 vm-agent 那么爽的另一个隐藏原因:vm-agent 天生支持在采集端直接做分布式分片,并且不需要任何复杂的第三方组件。

                    ┌──> vmagent-0 (只拉取 1/3 的 Target) ──┐
[海量监控目标 Target] ├──> vmagent-1 (只拉取 1/3 的 Target) ──┼─(remote_write)─> [VictoriaMetrics]
                    └──> vmagent-2 (只拉取 1/3 的 Target) ──┘

你只需要在部署 vm-agent 的多副本集群时,给它们加上两个极其简单的启动参数:

  • -remoteWrite.cluster.membersCount=3 (告诉它总共有 3 个分片)
  • -remoteWrite.cluster.memberNum=0/1/2 (告诉当前实例是第几个分片)

底层表现:这 3 个 vm-agent 实例会自动打散、平摊所有的监控目标。

  • 不仅提高了性能:每个实例的内存和网络开销直接暴跌到 1/3。
  • 而且在源头上干净利落:发往 VictoriaMetrics 的数据本身就是不重复且完美分片的,远端存储层甚至连“去重计算”的 CPU 损耗都省下来了。
时间点 (T) vm-agent 实例 0 (memberNum=0) vm-agent 实例 1 (memberNum=1) vm-agent 实例 2 (memberNum=2) 远端存储 (VictoriaMetrics) 接收状态
T1 内部利用一致性 Hash 算法计算,认领并抓取 Pod-A、Pod-D 的指标。 计算后,认领并抓取 Pod-B、Pod-E 的指标。 计算后,认领并抓取 Pod-C、Pod-F 的指标。 接收到 100% 完整但互不重复的全国/全集群业务指标流。
T2 remote_write 发送 A, D。 remote_write 发送 B, E。 remote_write 发送 C, F。 存储层极其轻松,无需做任何去重计算(Deduplication),来什么直接落盘什么。
  • 底层表现:如果集群里的 Pod 指标量有 3000 万,那么现在分摊到每个 vm-agent 身上只有 1000 万。内存和 CPU 开销直接暴跌到原来的1/3,实现了真正的横向可扩展(Scale Out)。

# 区别二、TSDB持久化

相比之下:

  • Prometheus 无法关闭 TSDB。它必须把数据解析成对象、建内存索引、塞入 Head Block,最后才能通过 remote_write 吐出来。

    Prometheus Agent 可关闭TSDB,官方文档: https://prometheus.io/docs/prometheus/latest/prometheus_agent/ (opens new window)

    2.32.0 版本后引入,Prometheus Agent 依然会写磁盘,但它彻底禁用了向本地 TSDB 历史块(Block)的写入,只在磁盘上保留最基础的 WAL(预写日志)用于断电容灾。

  • vm-agent 彻底扔掉了 TSDB 的概念。它在代码层面上彻底免去了“建索引”、“本地持久化”的逻辑,数据拉回来就是纯字节流,在环形缓冲区停留零点几秒后直接网络冲刷(Flush)给 VictoriaMetrics。

    • vm-agent 的设计要绝情得多:
      • 关于磁盘 WAL:vm-agent 默认连 WAL 都不写。它认为“为了极少发生的断电而让磁盘每秒承受几百兆的 I/O 写入”是本末倒置。数据拉回来直接进内存环形队列,网络发走,原地蒸发。只有在远端 VictoriaMetrics 真的挂了、网络彻底断开时,它才会临时把数据写入磁盘 Buffer。
      • 关于内存索引:vm-agent 不需要维持全量的内存时序树。它把指标看作纯粹的字节流,利用高度优化的无锁算法,拉过来就塞网络管子,根本不在内存里“定居”。

# 区别三、内存索引和历史缓存

# prometheus - 内存索引

prometheus中 内存索引本质上是一棵在内存中维护的、极为庞大的倒排索引树(Inverted Index Tree)。它的职责是:当你用一组标签去查指标时,能瞬间告诉你这个指标在内存里的哪块地方。

里面塞了什么?

每当你抓取一条带有新标签的指标,Prometheus 就会在内存索引里塞入三样东西:

  1. LabelName 到 LabelValue 的映射:比如 pod ——> nginx-abcd-1234。
  2. LabelValue 到 Series ID 的映射:由于字符串太长,Prometheus 会给每个唯一的指标组合分配一个全局唯一的 64 位数字 ID(叫做 Series ID)。
  3. 倒排索引表:记录哪些 Series ID 包含了 status="200"。

如果你的 K8s 集群非常大,Pod 经常发生漂移、重建(比如每次发布、或者 HPA 自动扩缩容),Pod 的名字就会不断改变(nginx-v1 变成 nginx-v2)。

  • 对 Prometheus 来说,只要有一个标签变了,这就是一条全新的指标序列(New Series)。
  • 结果就是:这棵内存索引树会只增不减地疯狂膨胀。即使那些死掉的 Pod 已经没有新数据进来了,它们的标签和索引依然永久常驻在你的 128G 内存里,直到内存被无情耗尽。

# prometheus - 历史缓存(Memory Chunks / Head Chunks)

当一个 Chunk 被 120 个数据点塞满后,它就会变成“只读”状态,并在内存里变成历史缓存(Memory Chunks)。

同时,Prometheus 会在内存里开辟一个新的、空的 Head Chunk 继续接收新数据。

这些塞满的只读 Chunks,会继续在内存里驻留很长时间。只有当时间累积到 2 小时后,Prometheus 内部的本地存储引擎才会启动一个大动作:把这 2 小时内所有指标的“历史缓存”统一打包,刷写到磁盘上(生成一个正式的 TSDB Block),随后才释放这部分内存。

对于vm-agent来说,它不要倒排索引,也不要在内存里憋 2 小时的历史 Chunk,它把指标当成冷酷的字节流,拉到就立刻吐给远端。

# 总结

指标维度 原生 Prometheus Prometheus Agent vm-agent (VictoriaMetrics)
本地历史块落盘 🟢 有(每 2 小时生成 Block) ❌ 无 ❌ 无
本地磁盘 WAL 预写 🟢 强制开启(高 I/O 吞吐) 🟢 强制开启(用于短时容灾) 🟡 默认关闭(仅在远端故障时触发 Buffer)
内存开销模型 极重(内存索引 + 历史缓存) 依旧较重(必须常驻全量内存时序索引) 极轻(流式无状态,内存只跟网络吞吐正相关)
大并发千万级指标表现 容易 OOM(需要 128G+ 甚至打爆) 缓解了磁盘,但高并发下依旧会 OOM 4C4G 稳如泰山
#vm-agent#prometheus#使用#替代
上次更新: 2026-07-01 15:23:28
最近更新
01
脏读、幻读
07-01
02
elasticsearch面试题
07-01
03
G1、ZGC有了解过吗?
07-01
更多文章>
Theme by Vdoing | Copyright © 2020-2026 HaC
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式