一句话总结
Prometheus 采用一种与直觉相悖但极其高效的设计--主动拉取(Pull)指标数据--配合标签化的数据模型和查询语言 PromQL,奠定了云原生指标监控领域的事实标准;Grafana 负责将数据可视化为看板,Alertmanager 负责将异常转化为可执行的告警.
前置回顾
第 02 篇在"设计"层面确定了方案:使用 Counter/Histogram 采集哪些数据,用 RED/USE 选择哪些指标,用 SLO 定义"好"的标准.但这些仍停留在纸面.本篇将这些设计落地--Counter 如何被采集,P99 如何用 PromQL 计算,SLO 如何转化为一条实际运行的告警规则.这是 Metrics 阶段从"设计"到"运行"的关键一步.
核心设计选择:Prometheus 的 Pull 模型
先理解一个让许多人感到意外的设计决策.监控数据从服务到监控系统有两种传输方向:
|
Prometheus 选择了 Pull 模型:服务只需暴露一个 HTTP 端点(约定路径为 /metrics),将当前指标以纯文本形式输出;Prometheus 按配置的间隔(如每 15 秒)主动发起抓取.一个 /metrics 端点的输出内容示例如下:
|
第 02 篇中的 Counter 和 Histogram 正是以这种纯文本格式对外暴露.Pull 模型在动态的 Kubernetes 环境中尤具优势:
| Pull 的优势 | 原因 |
|---|---|
| 目标健康状态可感知 | 抓取失败 = 服务不可达,抓取本身即一次健康检查 |
| 服务无需感知监控系统位置 | 服务仅负责暴露 /metrics,与监控系统地址解耦;不会因监控地址变更而需要修改代码 |
| 天然适配服务发现机制 | Kubernetes 中 Pod 频繁增删,Prometheus 自动发现新目标并开始抓取(详见下文) |
| 避免服务端过载 | 抓取频率由 Prometheus 控制,服务不会因大量推送流量而受影响 |
Pull 模型的局限:短生命周期任务如何处理?
Pull 模型假设目标"持续存在并等待被抓取".但某些任务运行时间极短(如一个几秒内完成的 CronJob,Prometheus 还未来得及抓取,任务便已结束).
这类场景可通过 Pushgateway 作为补充:短任务将指标推送至 Pushgateway 暂存,Prometheus 再从 Pushgateway 抓取.这是对 Pull 模型的补充手段,而非通用方案--过度使用会丧失"抓取失败 = 服务异常"的健康语义.
数据模型:指标名 + 标签
Prometheus 的数据模型是其能力的根基.每条时间序列由**指标名(Metric Name)和一组标签(Label)**唯一确定:
|
标签是维度.同一指标名下,标签的不同组合对应不同的时间序列.这使得可以从任意维度切片分析:"按 status 查看错误""按 service 查看流量""只关注 POST 请求"--全依赖标签的过滤与聚合能力.
指标名 + 标签类似于 Excel 数据透视表:指标名是"待统计的数值列",标签是"可以任意拖拽的维度".按地区查看?按产品查看?按地区×产品交叉查看?同一份数据,标签组合变化即视角变化--无需重新采集.
标签基数爆炸:最严重的陷阱,务必注意
标签值的种类越多,时间序列数量越多.若将高基数(High Cardinality)的值放入标签--例如 user_id,order_id,完整 URL,时间戳--序列数量将呈爆炸式增长(一百万用户即一百万条序列),直接耗尽 Prometheus 内存.
原则:标签仅存放"种类有限"的维度(如 method,status,service,这些值通常只有几种到几十种).需要按 user_id 排查?那是日志和追踪的职责(第 04-07 篇),而非指标的职责.违反此原则会导致监控系统故障.
PromQL:将第 02 篇的设计转化为查询
PromQL 是 Prometheus 的查询语言.不需要掌握全部语法,但有几个模式是日常排障的核心,恰好对应第 02 篇的指标设计.
使用 rate() 将 Counter 转换为速率
回顾第 02 篇的原则--Counter 的绝对值没有意义,速率才有.rate() 即用于此目的:
|
错误率:RED 中的 E
|
P99 延迟:RED 中的 D
第 02 篇指出延迟应看百分位,应使用 Histogram.PromQL 通过 histogram_quantile 从 Histogram 的桶数据中计算百分位:
|
至此,第 01 篇凌晨那条"下单 P99 超过 2 秒"的告警背后的 PromQL 逻辑已经清晰.RED 的三个指标对应三条查询,一一对应.
PromQL 的两种向量类型:瞬时向量与区间向量
一个常见的困惑:为什么 rate() 中需要写 [5m]?因为 rate 需要一段时间区间的数据才能计算速率(区间向量,Range Vector),而直接写 http_requests_total 获取的是当前单个瞬时点(瞬时向量,Instant Vector).
规则:**对 Counter 计算速率或增量的函数(rate,increase)均需要 [时间] 区间参数;直接查看 Gauge 当前值则不需要.**类型不匹配是 PromQL 报错的首要原因.
存储架构:Prometheus 内置存储的定位与局限
Prometheus 内置一个时序数据库(TSDB,Time Series Database),专为"大量数值 + 时间戳"场景优化,写入和查询性能均很高.但它刻意设计为本地,单机存储,由此带来两个限制:
- 不适合长期存储:默认保留约 15 天,本地磁盘无法承载数年数据量
- 非天然高可用:单机存储,该 Prometheus 实例故障则数据中断
这是刻意为之的设计选择:Prometheus 追求保持简单可靠的核心,将"长期存储,跨集群聚合,高可用"等需求交由专门的方案处理--Thanos 或 Mimir(将数据下沉至对象存储如 S3,实现近乎无限期,可水平扩展的存储;Mimir 采用 remote write 模型,Thanos 经典模式则通过 sidecar 将本地数据块上传至对象存储).
云原生组件的典型设计哲学
"核心做小做稳,扩展能力交由专门组件"--这一哲学在 CI/CD 系列中也有体现(第 03 篇 Kaniko 之于 Docker,第 08 篇 Terraform 状态后端).入门及中小规模场景,Prometheus 单机部署足够使用;当需要存储数年数据,跨数十个集群统一查询时,再引入 Thanos 或 Mimir.不必在起步阶段过度设计.
Grafana:统一可视化层
Prometheus 自带的界面功能较为基础.Grafana 是事实标准的可视化平台:它连接 Prometheus(以及后续将介绍的 Loki,Tempo)作为数据源,使用 PromQL 查询数据,将结果呈现为丰富的看板(Dashboard).
关键认知:Grafana 自身不存储数据,它仅是一个"查询 + 展示"的前端层.一张图表 = 一条 PromQL + 一种图形类型.第 02 篇的 RED 看板,即是将上述三条 PromQL 各配置一张图表组合而成.
Grafana 是统一门户,对第 08 篇至关重要
Grafana 支持同时接入 Prometheus(指标),Loki(日志),Tempo(追踪)三个数据源.这意味着可以在同一界面内从一张指标图表跳转到对应时间的日志,再跳转到相关的追踪--这正是第 08 篇"三支柱关联"得以实现的基础设施.
Grafana 不仅是画指标图表的工具,更是整个可观测性技术栈的统一入口.
告警:从被动查看到主动通知
看板是"主动查看"模式,但没有人能 7x24 小时盯屏幕.告警(Alerting)负责在异常发生时主动通知相关人员.Prometheus 的告警体系分两个步骤,职责分离清晰:
|
- Prometheus 负责"判断":告警规则的本质是一条 PromQL + 阈值 + 持续时间.条件成立则生成告警事件.
- Alertmanager 负责"处理通知":对告警进行去重(同一问题不重复发送),分组(相关告警合并为一条通知),按值班表路由,支持静默(维护期间暂停通知).
下面是一条将第 02 篇 SLO 落地的告警规则:
|
for 子句:告警设计中最容易被忽略的配置
for: 5m 表示"条件持续成立满 5 分钟才真正触发告警".缺少此配置,任何瞬时尖刺(一次网络抖动,一次 GC 停顿)都会在深夜触发通知--这是"告警疲劳"的主要原因之一.
几乎所有告警都应配置合理的 for 时长,以过滤转瞬即逝的抖动.如何设计"既不过度告警也不遗漏真实故障"的告警策略,是第 08 篇的核心话题.
Kubernetes 中的服务发现:Pull 模型自动化的关键
最后回应一个之前埋下的伏笔:Kubernetes 中 Pod 频繁增删与漂移(回顾 Kubernetes 笔记中的相关内容),Prometheus 如何知道该抓取哪些目标?答案是服务发现(Service Discovery)--Prometheus 直接对接 Kubernetes API,自动发现带有特定注解的 Pod/Service,动态将其加入抓取目标列表.Pod 启动即自动开始监控,Pod 终止即自动移除,全程无需手动修改配置.这正是 Pull 模型在动态环境中的核心优势.生产环境中通常使用 Prometheus Operator(配合 ServiceMonitor 资源)以声明式方式管理这一切--又是声明式思想(参见 GitOps 系列)的延伸.
快速回顾
- Pull 模型:Prometheus 主动抓取服务的
/metrics端点;优势在于"抓取失败 = 服务异常",解耦,适配服务发现;短生命周期任务通过 Pushgateway 补充 - 数据模型 = 指标名 + 标签,标签是任意可切片的维度;严禁将 user_id 等高基数值放入标签(序列爆炸将耗尽内存)
- PromQL 三板斧:
rate()将 Counter 转换为速率(R),5xx 比率计算错误率(E),histogram_quantile计算 P99(D);区间向量需带[5m] - 存储:内置 TSDB 性能高但限于本地与短期,长期存储与高可用交由 Thanos/Mimir--"核心精简,扩展外挂"
- Grafana 只做查询与展示,是接入 Prometheus/Loki/Tempo 的统一可视化门户(第 08 篇关联能力的基础)
- 告警两步走:Prometheus 判断(PromQL + 阈值 +
for),Alertmanager 处理通知(去重/分组/路由/静默);for用于过滤瞬时抖动 - Kubernetes 服务发现使 Pull 模型在动态环境中自动跟踪 Pod,常用 Prometheus Operator 以声明式方式管理
如何为服务暴露 /metrics 端点?需要手动拼接 Prometheus 文本格式吗?
不需要手动编写.各主流语言均有官方客户端库(Go,Java,Python,Node.js 等),只需在代码中声明指标(如 counter.Inc(),histogram.Observe(latency)),客户端库会自动维护数值并在 /metrics 端点以正确格式暴露.此外,许多现有组件配有Exporter(如 node_exporter 采集主机指标,mysqld_exporter 采集 MySQL 指标),用于将不支持 Prometheus 数据格式的系统转译为 /metrics 端点.手动编写格式的场景几乎不存在.
抓取间隔(scrape interval)应设为多少?间隔越短是否越实时越好?
常见设置为 15s ~ 60s,并非越短越好.间隔越短,数据点越密集 → 存储和计算负载成倍增加,而大多数指标并不需要秒级精度.此外,间隔需与告警的 for,PromQL 的 rate() 区间协调(rate 的区间通常取抓取间隔的 4 倍以上以获得足够样本).默认 15s 适合大部分场景;仅对延迟极为敏感的核心链路才考虑缩短间隔,并承担相应的资源成本.
动手练习
- 暴露 /metrics 端点:使用官方客户端库为一个示例服务添加
/metrics端点,声明一个请求 Counter 和一个延迟 Histogram,本地curl查看暴露的文本内容. - 运行 Prometheus 并查询:使用 Docker 运行一个 Prometheus 实例,配置其抓取该服务,在 Prometheus 自带界面执行
rate(http_requests_total[5m])查看曲线. - 编写 RED 查询:写出计算错误率和 P99 延迟的两条 PromQL,确认能返回正确结果--这即第 02 篇 RED 的 E 和 D.
- 搭建 Grafana 看板:接入 Grafana,将 R/E/D 三条查询各配置一张图表,组成一个"服务健康看板".
- 验证 for 子句的作用:编写一条"错误率 > 1% 持续 5 分钟"的告警规则,主动制造错误触发该规则;再移除
for: 5m,对比瞬时波动是否会触发误报--亲身体会for的作用.