2. Metric 设计基础:Prometheus Metric 类型详解及选型原则

在构建可观测性体系时,Metric(指标)是告警与监控的基石。Prometheus 提供了四种核心 Metric 类型:Counter、Gauge、Histogram 和 Summary。理解每种类型的语义、适用场景及局限性,是设计高效告警规则的前提。错误的 Metric 选型会导致告警失真、数据膨胀或查询性能下降。

2.1 四种 Metric 类型核心对比

类型 核心语义 典型值 可加减 适用场景
Counter 只增不减的累计值(重启可重置) 请求总数、错误总数 仅加法(rate/irate) 计数类、速率类告警
Gauge 可增可减的瞬时值 CPU 使用率、内存用量 加减均可 快照类、阈值类告警
Histogram 分桶统计 + 总和 + 计数 请求延迟分布 通过桶计算分位数 延迟/大小分布、SLO 计算
Summary 预计算分位数 + 总和 + 计数 请求延迟分位数(p99) 客户端侧聚合 已知分位数、低维度场景
选型第一原则:能用 Counter 不用 Gauge,能用 Histogram 不用 Summary。Counter 和 Histogram 天然支持 rate() 函数,是告警规则中最可靠的输入。

2.2 Counter:只增不减的累计器

Counter 是最常用的 Metric 类型,代表一个单调递增的计数器。它在服务重启时归零,但 PromQL 的 rate() 和 increase() 函数会自动处理重置逻辑。

// 定义:HTTP 请求总数
http_requests_total{method="GET", endpoint="/api/v1/users"} 1024

// 推荐告警用法:5分钟内错误率超过 5%
rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m]) > 0.05
避坑:不要对 Counter 直接使用 avg() 或 sum() 后做阈值比较,必须配合 rate() 或 increase() 转换为速率。直接比较原始值会因重启或时间窗口不同而产生误报。

2.3 Gauge:可上可下的瞬时表盘

Gauge 用于表示可以任意增减的瞬时值,如温度、内存使用量、队列深度。Gauge 不需要 rate() 转换,直接比较即可。

// 定义:当前内存使用字节数
node_memory_MemAvailable_bytes 8.5e+09

// 推荐告警用法:可用内存低于 500MB
node_memory_MemAvailable_bytes < 500 * 1024 * 1024
最佳实践:Gauge 适合设置静态阈值告警(如 > 90%),但应避免对 Gauge 做 rate() 计算——语义上不成立。如果需要对 Gauge 的变化速率告警,应使用 deriv() 函数。

2.4 Histogram:分布感知的分桶统计

Histogram 通过将观测值放入预定义的桶(bucket)中,同时记录总和(_sum)和计数(_count),从而在服务端计算分位数。它是 SLO 监控和延迟告警的核心工具。

// 定义:HTTP 请求延迟 Histogram
http_request_duration_seconds_bucket{le="0.1"}  500
http_request_duration_seconds_bucket{le="0.5"}  800
http_request_duration_seconds_bucket{le="1.0"}  950
http_request_duration_seconds_bucket{le="+Inf"} 1000
http_request_duration_seconds_sum                450.0
http_request_duration_seconds_count              1000

// 推荐告警用法:p99 延迟超过 1 秒
histogram_quantile(0.99,
  rate(http_request_duration_seconds_bucket[5m])
) > 1.0
关键优势:Histogram 的分位数计算在服务端完成,支持多维聚合(如按 service、route 分组)。桶的分布设计直接影响分位数精度——在目标阈值附近应加密桶。
Histogram 桶分布与分位数计算流程 原始观测值 延迟: 0.3s, 1.2s 0.8s, 2.5s ... 桶分配(Bucket) le=0.1 → 5 个请求 le=0.5 → 20 个请求 le=1.0 → 50 个请求 histogram_quantile(0.99) 在服务端按桶插值 输出: p99 ≈ 0.95s 支持多维 group by 设计要点: 桶的边界应覆盖目标 SLO 阈值(如 0.5s、1s),并在阈值附近加密(如 0.1、0.2、0.5、0.8、1.0)。 桶数量建议控制在 10~15 个,过多会增加存储开销,过少会降低分位数精度。

2.5 Summary:客户端预计算的分位数

Summary 在客户端直接计算分位数(如 p50、p90、p99),并将结果暴露为独立的 Metric 序列。它不依赖桶,因此无法在服务端进行多维聚合。

// 定义:Summary 暴露的分位数(客户端已算好)
rpc_duration_seconds{quantile="0.5"}  0.05
rpc_duration_seconds{quantile="0.9"}  0.12
rpc_duration_seconds{quantile="0.99"} 0.35
rpc_duration_seconds_sum              120.0
rpc_duration_seconds_count            2000

// 告警用法:直接比较分位数
rpc_duration_seconds{quantile="0.99"} > 0.5
Summary 的局限:无法对多个实例的 Summary 做 histogram_quantile 聚合。如果需要对 service 级别的全局 p99 告警,必须使用 Histogram。Summary 仅适用于已知分位数且不需要跨维度聚合的场景。

2.6 选型决策流程

以下决策树可帮助你在设计 Metric 时快速确定类型:

Metric 类型选型决策树 观测值是什么? 只增不减的计数? ✅ 使用 Counter 可增可减的瞬时值? ✅ 使用 Gauge 需要分布/分位数? 需要多维聚合? ✅ 使用 Histogram ⚠️ 使用 Summary 提示: Summary 仅用于已知分位数且无需跨实例聚合的场景(如单进程内部延迟)。绝大多数分布式系统应优先选择 Histogram。

2.7 选型原则总结

  1. Counter 优先原则:所有计数类指标(请求数、错误数、写入行数)一律使用 Counter。配合 rate() 函数可消除重启影响,是告警最稳定的输入。
  2. Gauge 仅用于快照:内存、CPU、队列深度等瞬时值用 Gauge。避免对 Gauge 做 rate(),语义错误。
  3. Histogram 是分布首选:需要延迟、大小分布或 SLO 计算时,优先使用 Histogram。桶设计要覆盖目标阈值并适当加密。
  4. Summary 谨慎使用:仅当无法接受 Histogram 的存储开销且不需要多维聚合时,才考虑 Summary。大多数场景下 Histogram 更灵活。
  5. 命名规范:Counter 以 _total 结尾,Histogram 桶以 _bucket 结尾,总和以 _sum 结尾,计数以 _count 结尾。遵循 Prometheus 命名约定可提升可读性。