4. 指标定义与建模:从黄金指标到 Prometheus 数据模型
聊到失效预警,第一个绕不开的问题就是:你到底要监控什么?
很多人一上来就堆指标,CPU、内存、磁盘、网络……全拉上。结果告警一响,全是噪音。我见过最夸张的项目,一天能收到两千条告警,运维团队直接选择“静默”——这其实比没监控更危险。
所以这一章,我们得把指标这件事彻底理清楚。从最经典的黄金指标,到自定义业务指标,再到怎么管好这些指标的“元数据”,最后落到 Prometheus 的数据模型上。嗯,一步步来。
4.1 黄金指标:四个维度看透系统
Google 的 SRE 团队总结过四个黄金指标——延迟、流量、错误、饱和度。说白了,这四个维度能覆盖绝大多数系统的健康状态。我个人习惯,不管接什么新系统,先拿这四个维度去套一遍,基本不会漏掉关键点。
| 指标 | 核心含义 | 常见度量方式 | 我踩过的坑 |
|---|---|---|---|
| 延迟 (Latency) | 请求从发出到收到响应的时间 | P50 / P95 / P99 分位延迟 | 只看平均值会掩盖长尾问题 |
| 流量 (Traffic) | 系统承载的请求量级 | QPS / RPS / 带宽 | 流量突降也可能是故障(比如上游熔断) |
| 错误 (Errors) | 请求失败的比率 | HTTP 5xx / 业务错误码 / 超时 | 显式错误 + 隐式错误(如返回 200 但内容为空)都要算 |
| 饱和度 (Saturation) | 系统资源被消耗的程度 | CPU 使用率 / 内存占用 / 队列深度 | 饱和度到 100% 才告警往往已经晚了 |
核心原则:黄金指标不是让你四个都抓,而是让你先问自己——这个系统如果出问题,用户最先感知到的是哪个维度?从那里开始。
举个例子。我在维护一个支付网关时,延迟 P99 从 200ms 涨到 2s,但平均延迟才 300ms。如果只看平均值,你根本不会发现异常。但用户已经在骂了。所以记住:延迟一定要看分位值,P99 比平均值真实得多。
4.2 自定义业务指标:把监控和钱挂钩
黄金指标能告诉你系统“活着”,但没法告诉你业务“赚不赚钱”。
我曾经帮一家电商公司做失效预警,技术指标全绿,但老板发现订单量在跌。为什么?因为下单接口返回了 200,但数据库写入失败了——这叫“静默错误”。
所以,你必须定义业务指标。比如:
- 订单成功率:下单请求中最终支付成功的比例
- 核心链路耗时:从点击“购买”到看到“支付成功”页面的总时长
- 用户登录失败率:连续 5 分钟内登录失败的次数占比
我的建议:业务指标不要超过 10 个。每多一个指标,就多一份维护成本和告警噪音。挑最核心的 3-5 个,盯死它们。
定义业务指标时,有个容易忽略的点:指标口径要统一。比如“订单成功率”,研发和运营的理解可能不一样。研发觉得“接口返回 200 就算成功”,运营觉得“用户付了钱才算成功”。我建议在指标元数据里明确写清楚计算逻辑,避免后续扯皮。
4.3 指标元数据管理:给指标上“身份证”
指标一多,管理就乱。你想想看,一个 Prometheus 实例里可能跑着几千个指标,三个月后你还能记得每个指标是干嘛的吗?
所以我们需要指标元数据。说白了,就是给每个指标配一张“身份证”。
| 元数据字段 | 说明 | 示例 |
|---|---|---|
| 指标名称 | 唯一标识 | http_request_duration_seconds |
| 指标类型 | Counter / Gauge / Histogram / Summary | Histogram |
| 所属域 | 业务 / 中间件 / 基础设施 | 中间件 |
| 计算口径 | 指标的计算逻辑说明 | 统计所有 HTTP 请求从接收到响应的时间 |
| 告警阈值 | 建议的告警触发条件 | P99 > 1s 持续 5 分钟 |
| 负责人 | 谁对这个指标负责 | @张三 |
注意:元数据管理不是一次性工作。指标变更(比如口径调整、阈值修改)一定要同步更新元数据。我曾经因为没更新口径,导致两个团队对同一个指标的理解完全相反,排查了三天才发现问题。
实践中,我习惯把指标元数据存在一个 YAML 文件里,纳入 Git 管理。每次修改都走 PR 评审,这样既有记录,又能追溯。
4.4 Prometheus 数据模型:理解底层存储逻辑
聊完指标定义,我们得看看 Prometheus 到底怎么存这些数据的。理解了数据模型,你写 PromQL 的时候才不会懵。
Prometheus 的数据模型核心就一句话:时序数据 = 指标名 + 标签集合 + 时间戳 + 样本值。
举个例子:
http_requests_total{method="GET", endpoint="/api/users", status="200"} 1024 @ 1700000000
这个序列表示:在时间戳 1700000000 时,GET 请求 /api/users 返回 200 的次数是 1024。
这里有几个关键点:
- 指标名:描述“是什么”,比如
http_requests_total - 标签:描述“哪个维度”,比如
method、endpoint、status - 时间戳:精确到毫秒
- 样本值:一个 float64 数值
为什么标签这么重要?因为 Prometheus 的查询、聚合、告警,全是靠标签来筛选的。你想想看,如果没有 method 标签,你怎么单独看 POST 请求的延迟?
设计原则:标签的基数(即不同取值的数量)要控制。比如 user_id 这种取值几百万的标签,千万别加到指标里——Prometheus 会直接撑爆。我见过有人把 ip 当标签,结果一个指标产生了上亿条时间序列,查询直接超时。
Prometheus 支持四种指标类型:
| 类型 | 特点 | 适用场景 |
|---|---|---|
| Counter | 只增不减(重启会重置) | 请求总数、错误总数 |
| Gauge | 可增可减 | CPU 使用率、内存占用、在线人数 |
| Histogram | 分桶统计,可计算分位值 | 请求延迟、响应大小 |
| Summary | 类似 Histogram,但分位值由客户端计算 | 需要精确分位值且能接受客户端开销 |
我个人更推荐用 Histogram 而不是 Summary。为什么?因为 Summary 的分位值在客户端算好了,你没法在服务端做跨实例聚合。而 Histogram 的桶数据可以聚合,灵活性高得多。
4.5 本章知识体系图
下面这张图把指标定义与建模的核心逻辑串起来了。从黄金指标出发,到自定义业务指标,再到元数据管理,最后落到 Prometheus 数据模型——每一步都环环相扣。
4.6 避坑指南:我踩过的三个坑
最后分享几个真实教训,希望能帮你少走弯路。
- 标签基数爆炸:我曾经把
request_id作为标签,结果 Prometheus 内存直接打满。记住:标签的取值数量要可控,一般建议不超过 10 万。 - 指标口径不一致:两个团队对“错误率”的定义不同,一个算 5xx,一个算所有非 200。最后告警对不上,排查浪费了两天。解决方案:元数据里写清楚计算逻辑。
- Histogram 桶设置不合理:默认桶范围太宽,导致 P99 计算不准确。我后来改成
[0.1, 0.5, 1, 2, 5, 10]秒,才真正反映出长尾问题。
一个小技巧:定义指标时,先问自己三个问题——这个指标能反映用户真实体验吗?它的标签基数可控吗?它的计算口径团队内统一吗?三个问题都回答“是”,再把它加进去。