4. Metric 设计基础:Counter、Gauge、Histogram、Summary 的选择与适用场景
在可观测性体系中,Metric 是量化系统状态与行为的核心手段。选错 Metric 类型会导致误判、告警风暴或 MTTR 复盘失真。本章深入剖析 Prometheus 体系下四种核心 Metric 类型——Counter、Gauge、Histogram、Summary——的设计意图、适用场景与 SRE 实战陷阱。
4.1 四种 Metric 类型核心对比
| 类型 | 语义 | 典型值 | 可加减 | 适用场景 |
|---|---|---|---|---|
| Counter | 只增不减的累计值 | 请求总数、错误总数 | 只能加 | 吞吐量、错误计数、事件次数 |
| Gauge | 可增可减的瞬时值 | CPU 使用率、内存用量 | 可加可减 | 资源水位、队列深度、连接数 |
| Histogram | 分桶统计分布 | 请求延迟分布、响应大小分布 | 分桶计数 | 延迟/尺寸的百分位估算、SLO 合规 |
| Summary | 预计算分位数 | p50/p90/p99 延迟 | 客户端计算 | 已知分位数、低数据量、精确百分位 |
SRE 黄金法则:Counter 用于“发生了多少次”,Gauge 用于“当前是多少”,Histogram/Summary 用于“分布长什么样”。混淆 Counter 与 Gauge 是 MTTR 复盘数据失真的首要原因。
4.2 Counter:只增不减的累计器
Counter 代表一个单调递增的计数器,重启时归零。SRE 最常犯的错误是直接对 Counter 原始值做告警,而非使用 rate() 或 increase() 计算速率。
# 错误:对 Counter 原始值设置阈值
http_requests_total > 1000 # 重启后必然触发
# 正确:使用速率
rate(http_requests_total[5m]) > 100 # 每秒请求数
Counter 适用清单:
- HTTP 请求总数、RPC 调用次数
- 错误/异常发生次数
- 任务执行次数、消息消费次数
- 写入/读取字节数累计
陷阱:不要用 Counter 表示“当前在线人数”或“当前队列长度”——这些值会下降,应使用 Gauge。Counter 下降意味着重置或溢出,会破坏 rate() 计算。
4.3 Gauge:瞬时快照
Gauge 反映系统在采样时刻的瞬时状态,可升可降。Gauge 的告警逻辑通常基于原始值或变化率。
# 直接对 Gauge 原始值告警
node_memory_MemAvailable_bytes < 1e9 # 可用内存低于 1GB
# 对 Gauge 变化率告警(突增/突降)
deriv(node_memory_MemAvailable_bytes[5m]) < -5e7 # 内存下降速率过快
Gauge 适用清单:
- CPU/内存/磁盘使用率
- 当前活跃连接数、goroutine 数
- 队列当前深度、缓冲池水位
- 温度、风扇转速、电压
- 业务指标:当前在线用户、库存量
4.4 Histogram:分布估算
Histogram 将观测值放入预定义桶(bucket),通过桶计数估算百分位数。适合延迟、响应大小等需要了解分布特征的场景。
# 定义 Histogram 桶(单位:秒)
http_request_duration_seconds_bucket{le="0.1"} 1200
http_request_duration_seconds_bucket{le="0.5"} 3400
http_request_duration_seconds_bucket{le="1.0"} 4100
http_request_duration_seconds_bucket{le="+Inf"} 4500
# 估算 p99
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
Histogram 设计要点:
- 桶边界需覆盖业务 SLO 范围(如 SLO 为 200ms,则在 200ms 附近加密桶)
- 桶数量建议 10-15 个,过多增加存储开销
- +Inf 桶必须存在,用于兜底
- Histogram 在服务端计算分位数,适合多实例聚合
MTTR 复盘价值:Histogram 能揭示“慢请求是否集中在特定时间段或实例”,帮助定位故障根因。例如 p99 突增但 p50 正常,说明尾部延迟恶化,可能指向某台慢实例。
4.5 Summary:预计算分位数
Summary 在客户端直接计算分位数并暴露结果,适合对精度要求高、数据量可控的场景。
# Summary 暴露的分位数(客户端预计算)
rpc_duration_seconds{quantile="0.5"} 0.052
rpc_duration_seconds{quantile="0.9"} 0.098
rpc_duration_seconds{quantile="0.99"} 0.152
Summary 与 Histogram 对比:
| 维度 | Histogram | Summary |
|---|---|---|
| 分位数计算位置 | 服务端(PromQL) | 客户端(应用内) |
| 聚合能力 | 支持多实例聚合 | 不支持聚合(相加无意义) |
| 精度控制 | 依赖桶边界设计 | 可指定误差范围 |
| 存储开销 | 桶数 × 标签基数 | 分位数数量 × 标签基数 |
| 适用场景 | 多实例聚合、SLO 监控 | 单实例精确分位数、低基数 |
陷阱:Summary 的分位数无法在 PromQL 中跨实例求和。如果需要对多个实例的 p99 取全局 p99,必须使用 Histogram。Summary 适合“每个实例独立看分位数”的场景。
4.6 选择决策流程
以下 SVG 流程图帮助 SRE 工程师快速选择正确的 Metric 类型:
4.7 实战案例:MTTR 复盘中的 Metric 选择
某电商系统在双十一期间出现支付接口延迟飙升,SRE 团队复盘时发现以下 Metric 设计问题:
| 原始设计 | 问题 | 优化方案 |
|---|---|---|
payment_latency_ms (Gauge) |
Gauge 无法反映延迟分布,仅记录瞬时值,无法计算 p99 | 改为 Histogram,桶边界设为 [50, 100, 200, 500, 1000, 2000, 5000] |
payment_errors_total (Counter) |
直接对原始值告警,重启后误报 | 使用 rate(payment_errors_total[5m]) 计算错误率 |
active_connections (Counter) |
连接数会下降,Counter 语义错误 | 改为 Gauge,正确反映当前连接数 |
复盘结论:错误的 Metric 类型选择导致 MTTR 复盘时无法准确识别“延迟分布恶化”这一根因。优化后,通过 Histogram 的 p99 突增定位到某台数据库实例的慢查询,MTTR 从 45 分钟降至 12 分钟。
4.8 最佳实践清单
- Counter 必配 rate():所有 Counter 告警和图表都应使用
rate()或increase(),避免重启干扰 - Gauge 关注变化率:除原始值告警外,增加
deriv()或delta()检测突增/突降 - Histogram 桶对齐 SLO:桶边界应覆盖 SLO 目标值,并在目标值附近加密
- Summary 慎用聚合:明确 Summary 不可跨实例求和,多实例场景优先选 Histogram
- 标签基数控制:无论哪种类型,标签基数建议控制在 1000 以内,避免高基数爆炸
- 统一命名规范:类型后缀(_total、_bucket、_count、_sum)必须遵循 Prometheus 命名约定
SRE 检查清单:每次新增 Metric 前,问自己三个问题——(1) 这个值会下降吗?(2) 我需要分布还是均值?(3) 需要跨实例聚合吗?答案直接决定 Metric 类型。