第 1 部分导论 · Prometheus 架构总览

打开 Prometheus 的整体骨架——它由哪几块组成、各块怎么接线、以及贯穿其设计的两个根本选择:pull 模型和「单机自足」。这一章给出后续所有章节的坐标系。

作者 David更新于 第 6 篇(共 52 篇)

第 1 部分导论 · Prometheus 架构总览

第 0 部分画了数据的一生。从这一部分起,我们打开 Prometheus 的源码,先看它的整体骨架——后面每一章都会落在这张图的某个位置上。

五大块

Prometheus 是一个二进制(cmd/prometheus/main.go),内部由五块组成:

图表加载中…
块目录职责本专栏
服务发现discovery/动态找出要抓的目标本部分
抓取scrape/按周期拉 /metrics、解析本部分
存储tsdb/时序数据落盘与检索第 3 部分
查询promql/PromQL 解析与执行第 4 部分
规则rules/预聚合与告警规则第 5 部分

注意这五块之间靠接口解耦,而不是直接调用——这是读懂 Prometheus 架构的钥匙。 最关键的两个接口在 storage/:

  • storage.Appender —— 抓取只管“把采样点交出去”,不关心背后是 TSDB、远程写、还是测试假实现。
  • storage.Querier —— 查询引擎只管“按标签匹配器要 series”,不关心数据从内存还是磁盘来。

于是“采集”和“存储”、“存储”和“查询”之间是可替换的边界。这也是 Thanos、Mimir 这类项目能“把 Prometheus 的存储换掉、复用它的抓取和 PromQL”的原因——边界处就是生态的接口。

根本选择一:pull 而非 push

Prometheus 最著名的设计取舍:它主动去抓你,而不是你推给它。

pull 让 Prometheus 掌握主动权,这带来一串连锁的好处——理解这一点,才能理解为什么它长成现在这样。

  • 目标列表是“真相” —— Prometheus 通过服务发现知道应该有哪些目标。抓不到 = 目标出问题了。如果是 push,你永远不知道“没收到数据”是因为服务挂了还是因为它根本没部署。
  • 抓取即健康检查 —— 每次抓取的成败,被自动记成一个 up 指标(源码 scrape/scrape.go:2044)。你不用额外配存活探测,up == 0 就是它挂了。这是个极优雅的副产品。
  • 不会被打爆 —— 抓取节奏由 Prometheus 定(如 15s 一次)。客户端就算疯狂产生指标,也只是让那一次抓取变大,不会像 push 那样瞬间打垮服务端。
  • 易于调试 —— /metrics 是个普通 HTTP 端点,你 curl 一下就能看到这个服务当前所有指标。这个“随时可自查”的性质极其实用。

代价:Prometheus 必须网络可达每个目标。这在短命的批处理任务(跑完就没了,来不及被抓)、NAT/防火墙后的客户端上行不通——于是有了 Pushgateway 这类补丁。但补丁是例外,pull 是主线。

根本选择二:单机自足,不搞分布式

另一个同样重要、却常被忽略的选择:

一个 Prometheus 实例是完全自足的单机进程:自己发现、自己抓、自己存(本地磁盘)、自己查。它刻意不做分布式存储、不做集群共识。

这在“什么都要云原生分布式”的年代显得反直觉,但理由很硬:监控系统必须比被监控系统更可靠。如果 Prometheus 自己是个需要共识、需要协调、可能脑裂的分布式系统,那么当基础设施出问题时,它自己也会挂——而那恰恰是你最需要它的时刻。

单机自足意味着:没有外部依赖 = 没有额外的故障模式。你的 etcd 挂了、网络分区了,Prometheus 依然能抓到它够得着的目标、依然能查本地数据、依然能告警。这是一个用“能力上限”换“可靠性下限”的清醒取舍。

代价当然有:单机容量有限、数据不高可用。业界的解法不是“把 Prometheus 改成分布式”,而是在它之上叠一层——跑多个独立实例(冗余),用 Thanos / Mimir 做长期存储和全局查询。保持核心简单,把复杂性推到外层,这个思路值得记住。

一次抓取的完整链路

把五块串起来,一次抓取的实际链路是:

  1. discovery/ 吐出目标列表(如 K8s 里所有带某注解的 pod)。
  2. relabeling 对目标做改写 / 过滤(决定最终抓谁、带什么标签)。
  3. scrape/ 的 scrapePool(源码 scrape/scrape.go:84)为每个目标起一个 scrapeLoop(scrape.go:828),它的 run()(scrape.go:1263)就是那个按周期循环抓取的心脏。
  4. 抓回文本 → 解析 → 再做一轮 metric relabeling → 通过 storage.Appender 交给 TSDB。
  5. 顺带自动写入几个元指标:up、scrape_duration_seconds、scrape_samples_scraped 等(scrape.go:2044 起)——后面会讲这些是排查采集问题的第一现场。

这条链路就是第 1 部分剩下几章的顺序:数据模型 → 指标类型 → 暴露格式 → 服务发现 → 抓取循环 → relabeling。

小结与下一章

Prometheus 是一个自足的二进制,五块组成:服务发现(discovery/)、抓取(scrape/)、存储(tsdb/)、查询(promql/)、规则(rules/),彼此靠 storage.Appender/storage.Querier 两个接口解耦(边界处即生态接口,Thanos/Mimir 由此而来)。两个根本选择:pull 模型(目标列表即真相、抓取即健康检查(up)、不会被打爆、可 curl 自查;代价是要网络可达)、单机自足(监控必须比被监控更可靠 → 无外部依赖 = 无额外故障模式;容量与高可用推到 Thanos/Mimir 那层解决)。

骨架有了,先看数据本身长什么样——Prometheus 的数据模型,以及它为省内存做到了什么地步。👉 数据模型。

参考资料

  • [1] Prometheus 源码 cmd/prometheus/main.go(五块的接线)、storage/interface.go(Appender/Querier)。
  • [2] Prometheus 源码 scrape/scrape.go(scrapePool:84、scrapeLoop:828、run:1263、up:2044)。
  • [3] Prometheus 官方文档 docs/index.md、docs/getting_started.md。

本页目录