很多团队在监控上踩的第一个坑,不是工具选错了,而是把监控当成“装个仪表盘”就结束了。等到半夜故障真的来了,才发现图表很漂亮,但该响的告警没响,或者响得太多,运维干脆把手机静音了。Prometheus + Grafana 这套组合之所以流行,不只是因为它开源、轻量,更因为它逼迫你从指标模型开始,认真思考“到底要监控什么”和“怎么判断异常”。

这篇文章不会把 Prometheus 的每个配置项再讲一遍,而是想从工程落地的角度,把这套体系的建设路径理清楚——从指标选型、可视化设计,到告警规则和告警路由,最后形成一套真正能用的监控闭环。
为什么是 Prometheus + Grafana
传统监控工具(比如 Zabbix)更擅长以主机为中心,对 CPU、内存、磁盘这种固定采集项做阈值判断。但今天大部分服务已经跑在容器和微服务架构上,监控对象变成了动态的 Pod、服务接口延迟、业务错误率等。Prometheus 从一开始就设计为面向服务发现和时序数据,它的拉模型(pull)让每个服务自己暴露指标,监控系统定期抓取,天然适配 Kubernetes 这类动态环境。
Grafana 则是可视化层的“瑞士军刀”。它不绑定 Prometheus,但和 Prometheus 配合得最紧密,因为 PromQL 的表达能力足够强大,而 Grafana 的模板变量和仪表盘复用能力,可以让你用同一套图表监控不同环境、不同服务。
但真正让这套体系“工程化”的关键,是 Prometheus 的指标模型和 Alertmanager 的告警管理。理解这两点,才能避免“监控数据爆炸”和“告警地狱”。
指标模型:不是所有数据都能叫指标
很多团队一开始会用 SDK 把日志里的一些数字随手暴露出来,比如当前在线用户数、某个接口的请求量。但如果不理解 Prometheus 的四种指标类型,之后做聚合和告警就会非常痛苦。
| 指标类型 | 典型场景 | 关键行为 | 常见错误 |
|---|---|---|---|
| Counter | 请求总数、错误次数 | 只增不减,重启归零 | 用 Counter 做绝对值告警,应用重启后归零误判 |
| Gauge | 内存使用量、连接数 | 可增可减 | 对瞬时尖峰不做平滑就告警,群发报警 |
| Histogram | 请求延迟分布 | 分桶统计,可算分位数 | 桶设置不合理,导致分位数误差大 |
| Summary | 客户端计算分位数 | 直接暴露分位数 | 无法聚合多实例,几乎不再推荐使用 |
这个表格里的“常见错误”是真实项目中反复出现的。比如,一个服务重启后 Counter 归零,如果你用 increase() 去算速率,Prometheus 会自动处理重置,但如果你直接对 Counter 的值做阈值判断,就会误报。另一个典型问题是 Histogram 的桶(bucket)设计。如果你想知道 P99 延迟,但最大的桶只到 500ms,那所有超过 500ms 的请求都会被归入同一桶,P99 就永远算不准。
在 SDK 暴露指标时,最好先想清楚:这个数据是累积的,还是瞬时状态?需要跨实例聚合吗?如果需要算分位数,用 Histogram 并合理设桶。如果是对外部系统做健康检查,用 Gauge 就够了。
PromQL:让查询变成排查工具
很多同学把 PromQL 当成 SQL 的翻版,写的时候习惯性地套用“select where group by”。但 PromQL 是为时序数据设计的,强大的地方在于瞬时向量和范围向量的运算,以及 rate()、increase()、histogram_quantile() 这些函数。
一个典型的场景:线上某个接口的响应变慢,但单个实例的延迟看起来正常。你可能会这样查:
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{job="api-server"}[5m])) by (le))
这行 PromQL 的意思是:取最近 5 分钟所有实例的请求延迟分桶数据,按桶(le)聚合,再计算 P99。注意这里用的是 sum(rate(...)) by (le),而不是先算每个实例的分位数再平均——后者在数学上没有意义,也是很多人刚开始用 Prometheus 时最容易犯的错误。
类似的,如果想看某个接口的 QPS 和错误率,可以组合使用:
rate(http_requests_total{job="api-server", handler="/api/order"}[5m])
rate(http_requests_total{job="api-server", handler="/api/order", status=~"5.."}[5m])
/ rate(http_requests_total{job="api-server", handler="/api/order"}[5m])
这些查询不只是用在 Grafana 里画图,更是排查问题时快速定位的利器。而 Grafana 的模板变量(比如 $job、$instance)可以让这些查询在仪表盘上复用,不用每次都手写。
Grafana 仪表盘:从“能看”到“一看就懂”
Grafana 的仪表盘很容易做出花里胡哨的效果,但真正好用的仪表盘讲究“信息密度”和“一眼定位”。我见过很多团队把几十个服务的信息堆在一个仪表盘里,每个图都很小,出了问题根本看不清。
一个实用的设计原则是:
- 服务概览仪表盘:每个服务一个,放在最上层,包含 RED(Rate, Errors, Duration)和资源使用情况。
- 基础设施仪表盘:按节点或集群汇总 CPU、内存、磁盘、网络。
- 中间件仪表盘:针对数据库、缓存、消息队列等,暴露其自身指标。
变量化是 Grafana 的精髓。比如在服务概览仪表盘里,用 $service 变量切换不同服务,用 $interval 调整时间范围。这样只用一套模板就能覆盖所有服务,维护成本极低。
另外,不要把所有指标都画成折线图。对于错误率,用状态面板(Stat)或仪表盘(Gauge)更直观;对于 QPS,可以用 Singlestat 或 Bar gauge。颜色和阈值也要提前设计好,比如延迟超过 500ms 用黄色,超过 1s 用红色。
告警体系:从“响了就行”到“有效闭环”
告警是整个监控体系里最容易“烂尾”的部分。很多团队 Prometheus 规则写得满满当当,但真正出问题时要么被淹没在告警风暴里,要么告警发了没人处理,最后变成“狼来了”。
Prometheus 的告警由两部分组成:在 Prometheus 中定义告警规则,由 Alertmanager 负责分组、抑制、静默和发送通知。很多人只关注规则怎么写,却忽略了 Alertmanager 的路由配置,这是告警混乱的根源。
一个典型的规则看起来像这样:
groups:
- name: api-server
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "API server error rate > 5%"
description: "Service {{ $labels.job }} has error rate {{ $value }}%"
这里的 for: 5m 很重要,它表示持续 5 分钟才触发告警,避免瞬时抖动。但很多人会忽略 severity 标签,导致 Alertmanager 无法按严重级别路由。
Alertmanager 的核心是路由树。一个典型的配置思路是:
- 按
severity区分:critical 的走电话或即时通知,warning 的走邮件或 Slack。 - 按
team分组:让不同团队只收到自己服务的告警。 - 利用抑制规则:比如节点宕机时,抑制该节点上所有服务的告警,避免重复报警。
另一个容易被忽略的点是告警的有效性。每隔一段时间,团队应该回顾告警历史,关掉那些从未触发过或经常误报的规则,优化阈值。告警不是越多越好,而是每次响都值得有人去看。
常见误区与避坑指南
结合过去在多个团队里观察到的现象,有几个误区几乎每次都会出现:
1. 把所有指标都长期保存
Prometheus 本地存储不适合长期归档,默认保留 15 天。有些团队把采集间隔设到 5 秒,存储压力巨大。合理做法是:高价值指标保留 30 天,长周期趋势数据通过远程存储方案(如 Thanos、VictoriaMetrics)归档。
2. 过度依赖平均值
延迟监控如果只看平均值,会掩盖长尾问题。必须用分位数,并且 Histogram 的桶要覆盖核心 SLA 范围。例如,如果 SLA 是 200ms,桶必须覆盖 0-200ms 且足够细。
3. 告警规则与业务脱节
技术指标(如 CPU 使用率)往往不是业务受损的直接信号。应该优先从服务端错误率、用户可见的延迟、业务订单量等指标入手,再向下拆解到基础设施。
4. 把 Grafana 当监控源
Grafana 只是展示层,它不能取代 Prometheus 的告警。监控系统必须依赖 Prometheus 的规则引擎,Grafana 的告警功能更适合临时性或非关键场景。
方案对比:什么时候该用,什么时候该换
虽然 Prometheus + Grafana 是现在的主流,但不是所有场景都适合。下面这张表总结了几种常见选择:
| 方案 | 适用规模 | 优点 | 缺点 |
|---|---|---|---|
| Prometheus 单机 | 中小规模(<1000 节点) | 部署简单,社区强大 | 单点故障,长期存储困难 |
| Prometheus + Thanos/VictoriaMetrics | 中大规模,需长期存储 | 高可用,降采样,多集群聚合 | 运维复杂度增加 |
| Zabbix | 传统 IDC,主机监控为主 | 成熟稳定,网络监控能力强 | 容器化支持弱,二次开发成本高 |
| 商业 SaaS(如 Datadog) | 多团队,不想自建监控基础设施 | 开箱即用,集成丰富 | 成本高,数据控制权有限 |
对于大部分处于成长阶段的互联网业务团队,Prometheus 单机或加上 Thanos 做简单扩展,已经足够支撑很长一段时间。只有当监控节点数超过 1000 个,或者需要跨地域、多集群统一查询时,才需要考虑更复杂的架构。
从零开始的落地路径
如果你现在要在一个新启动的项目里建立监控体系,可以按这个节奏走:
- 先确定最关键的几个服务,为它们暴露 RED 指标(Rate, Errors, Duration),并配置好 Prometheus 抓取。
- 搭建第一个 Grafana 服务概览仪表盘,用变量支持多服务切换。
- 基于错误率和延迟,设置 2-3 条核心告警规则,配置 Alertmanager 只发 critical 级别到即时通知渠道。
- 让团队在 on-call 中体验一周,根据误报和漏报调整阈值和告警持续时间。
- 再逐步扩大到基础设施和中间件监控,并引入远程存储解决长期查看问题。
这个过程中,保持“少而精”的原则:先让告警有质量,再补全图表。监控体系不是一次性建设完就永远不变的,它需要随着业务和架构的演进不断调整。
说到底,Prometheus + Grafana 只是工具,真正决定监控质量的,是团队对可观测性的理解和持续投入的意愿。当你有一天半夜被叫醒,能够快速定位问题而不是对着几十条告警发呆,这套体系才算真正建成了。
原创文章,作者:fudengji,如若转载,请注明出处:https://fudengji.cn/article/445/