4. Metric Design 基础:什么是 Metric,Counter、Gauge、Histogram、Summary 的区别与选择

在可观测性体系中,Metric(指标)是描述系统状态与行为的数值化快照。它通过时间序列的形式记录系统在某一时刻或某一时间窗口内的特征,是告警、监控与容量规划的核心数据源。理解 Metric 的本质及其四种基本类型——Counter、Gauge、Histogram、Summary——是设计可靠告警规则与降噪策略的前提。

4.1 什么是 Metric

Metric 本质上是一个带时间戳的数值,通常由以下三部分构成:

  • Metric Name(指标名称):如 http_requests_total,描述被测量的对象。
  • Labels(标签):键值对,用于区分同一指标的不同维度,如 method="GET"、status="200"。
  • Value(数值):在特定时间点的测量结果,如 1024。

一个典型的 Metric 样本在 Prometheus 中表示为:

http_requests_total{method="POST", handler="/api/v1/order"} 1280

Metric 的设计遵循“单一职责”原则:一个指标只描述一种系统行为或状态,避免将多个语义混合到同一个指标中。例如,不要用同一个指标既记录请求总数又记录错误数,而应拆分为 http_requests_total 和 http_requests_errors_total。

设计要点: Metric 的标签基数(Label Cardinality)直接影响存储与查询性能。避免将用户 ID、请求 ID 等高基数值作为标签,否则会导致时间序列爆炸。

4.2 四种核心 Metric 类型

Prometheus 生态定义了四种基础 Metric 类型,每种类型对应不同的数据采集与聚合语义。下表从核心特征、适用场景与典型示例三个维度进行对比:

类型 核心特征 适用场景 典型示例
Counter 只增不减(重启后归零) 累计计数,如请求数、错误数、任务完成数 http_requests_total
Gauge 可增可减,反映当前值 瞬时值,如内存使用率、连接数、温度 node_memory_usage_bytes
Histogram 分桶统计,记录分布 延迟、请求大小等需要分位数的场景 http_request_duration_seconds
Summary 预计算分位数,客户端侧聚合 已知分位数需求,且无法在服务端聚合的场景 rpc_duration_seconds

4.3 Counter:只增不减的累计器

Counter 是最基础的 Metric 类型,其值只能单调递增(进程重启时重置为 0)。它适用于记录累计发生次数,如 HTTP 请求总数、数据库查询次数、任务执行成功数。

关键特性:

  • 使用 rate() 或 increase() 函数计算时间窗口内的变化速率。
  • 不能直接用于反映当前状态,如“当前在线人数”。
  • 典型告警场景:rate(http_requests_errors_total[5m]) > 0.1 表示错误率超过 10%。
# 定义 Counter 指标
http_requests_total{method="GET", endpoint="/health"} 1024

# 查询过去 5 分钟的平均每秒请求数
rate(http_requests_total[5m])

4.4 Gauge:可增可减的瞬时值

Gauge 用于记录可以上下波动的瞬时测量值,如 CPU 使用率、内存占用、当前活跃连接数、队列深度。它不关心历史累计,只反映“此时此刻”的状态。

关键特性:

  • 直接使用原始值进行告警,如 node_memory_usage_bytes > 1e10。
  • 支持 avg()、max()、min() 等聚合函数。
  • 典型告警场景:node_cpu_seconds_total{mode="idle"} < 0.2 表示 CPU 空闲率低于 20%。
# 定义 Gauge 指标
node_memory_usage_bytes{host="web-01"} 8589934592

# 查询当前内存使用率(百分比)
(node_memory_usage_bytes / node_memory_total_bytes) * 100

4.5 Histogram:分桶统计的分布利器

Histogram 将观测值分配到预定义的桶(Bucket)中,同时记录所有观测值的总和与计数。它适用于需要了解数据分布特征的场景,如请求延迟、响应大小。

关键特性:

  • 服务端计算分位数(如 P50、P99),支持聚合多个实例的数据。
  • 需要预先定义桶边界(如 {0.1, 0.5, 1.0, 2.5, 5.0})。
  • 典型告警场景:histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 2.0 表示 P99 延迟超过 2 秒。
# 定义 Histogram 指标(桶边界为 0.1, 0.5, 1.0, 2.5, 5.0, +Inf)
http_request_duration_seconds_bucket{le="0.1"} 240
http_request_duration_seconds_bucket{le="0.5"} 850
http_request_duration_seconds_bucket{le="1.0"} 920
http_request_duration_seconds_bucket{le="+Inf"} 1000
http_request_duration_seconds_sum 450.2
http_request_duration_seconds_count 1000

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

Summary 在客户端直接计算并暴露预定义的分位数(如 P50、P90、P99),同时记录总和与计数。它适用于无法在服务端聚合分位数的场景,或对分位数精度有严格要求的场景。

关键特性:

  • 分位数在客户端侧计算,服务端无法跨实例聚合。
  • 需要指定分位数列表(如 {0.5, 0.9, 0.99})和滑动窗口。
  • 典型告警场景:rpc_duration_seconds{quantile="0.99"} > 1.0 表示该实例的 P99 延迟超过 1 秒。
# 定义 Summary 指标(预计算 P50、P90、P99)
rpc_duration_seconds{quantile="0.5"} 0.12
rpc_duration_seconds{quantile="0.9"} 0.45
rpc_duration_seconds{quantile="0.99"} 1.02
rpc_duration_seconds_sum 450.2
rpc_duration_seconds_count 1000

4.7 类型选择决策流程

以下 SVG 图展示了从业务需求到 Metric 类型选择的决策路径,帮助你在实际设计中快速定位正确的类型:

Metric 类型选择决策流程 Metric 类型选择决策流程 业务需求定义 数据是否只增不减? 是 Counter 否 需要分布信息? 否 Gauge 是 能服务端聚合? 是 Histogram 否 Summary 说明:Counter 用于累计计数,Gauge 用于瞬时值,Histogram 用于服务端可聚合的分布,Summary 用于客户端预计算分位数。

4.8 类型对比与选择建议

在实际的 Metric Design 中,选择错误的类型会导致告警不准确或查询性能下降。以下从多个维度对比四种类型,帮助你做出正确选择:

对比维度 Counter Gauge Histogram Summary
数据语义 累计值 瞬时值 分布统计 预计算分位数
聚合能力 支持 rate/increase 支持 avg/max/min 支持服务端分位数 不支持跨实例聚合
存储开销 低(1 个时间序列) 低(1 个时间序列) 中(桶数 + 2 个辅助序列) 中(分位数 + 2 个辅助序列)
分位数精度 不适用 不适用 受桶边界影响 客户端精确计算
典型告警 错误率、请求速率 资源使用率、连接数 P99 延迟、响应大小 单实例 P99 延迟
常见误区: 不要用 Gauge 记录累计值(如总请求数),否则重启后数据丢失且无法计算速率。同样,不要用 Counter 记录瞬时值(如当前内存使用量),因为 Counter 的只增特性无法反映下降趋势。

4.9 实践建议:从告警降噪角度选择类型

在《变更失败率》课程背景下,Metric 类型的选择直接影响告警的准确性与降噪效果:

  • 变更失败率计算:使用 Counter 记录部署次数与失败次数,通过 rate() 计算失败率,避免因重启导致的计数重置。
  • 部署后延迟监控:使用 Histogram 记录请求延迟,通过 histogram_quantile 计算 P99 延迟,比平均值更能反映长尾问题。
  • 资源饱和度告警:使用 Gauge 记录 CPU/内存使用率,设置静态阈值告警,避免因速率计算引入的延迟。
  • 跨实例聚合:优先选择 Histogram 而非 Summary,因为 Histogram 支持服务端聚合,便于在集群级别计算分位数。
核心原则: 选择 Metric 类型时,先回答三个问题:数据是累计还是瞬时?是否需要分布信息?分位数能否在服务端聚合?答案将直接导向正确的类型。