4. 聚合操作符实战:sum、avg、min、max、count、stddev、topk、quantile_over_time

聚合操作符是 PromQL 从原始时间序列数据中提取业务语义的核心工具。在告警规则编写中,聚合操作符决定了“谁触发告警”以及“告警的严重程度如何计算”。本章将逐一拆解 8 个最常用的聚合操作符,并结合收敛场景给出工程化建议。

4.1 聚合操作符分类与适用场景

聚合操作符按计算维度可分为三类:集合型(sum、count)、统计型(avg、min、max、stddev)、排序型(topk、quantile_over_time)。下表列出了各操作符的核心用途与典型告警场景:

操作符 类型 核心用途 典型告警场景
sum 集合型 对维度值求和,常用于总量统计 总请求量、总错误数、总 CPU 使用率
avg 统计型 计算平均值,消除毛刺 平均延迟、平均负载、平均错误率
min 统计型 取最小值,关注最差情况 最低可用副本数、最小磁盘剩余空间
max 统计型 取最大值,关注峰值 最大延迟、最高 CPU 使用率
count 集合型 统计非空序列数量 存活实例数、异常指标数
stddev 统计型 计算标准差,衡量波动 延迟抖动、负载不均衡度
topk 排序型 返回 Top K 序列 最高延迟的 5 个实例、错误最多的 3 个服务
quantile_over_time 排序型 在时间窗口内计算分位数 P99 延迟、P95 错误率
工程建议:在告警表达式中,优先使用 avg 或 quantile_over_time 代替 sum 做阈值判断,因为总量容易受实例数变化影响,导致误告警。

4.2 集合型操作符:sum、count

sum 是最常用的聚合操作符,用于将多个时间序列的值相加。在告警中,sum 通常配合 by 子句保留关键维度,避免过度聚合丢失上下文。

# 按 service 维度聚合总请求量
sum by (service) (rate(http_requests_total[5m]))

# 按 region 维度聚合总错误数
sum by (region) (rate(http_errors_total[5m]))

count 用于统计满足条件的序列数量,常用于检测实例数是否低于预期:

# 统计当前存活的实例数
count by (service) (up == 1)

# 统计延迟超过 500ms 的实例数
count by (service) (http_request_duration_seconds > 0.5)
避坑提示:count 统计的是时间序列数量,不是数值总和。如果指标带有多个标签(如 instance、method、path),count 结果可能远大于实际实例数,务必使用 by 子句缩小维度。

4.3 统计型操作符:avg、min、max、stddev

统计型操作符用于描述数据分布的中心趋势和离散程度。在告警收敛中,avg 和 max 的组合使用最为常见:

# 平均 CPU 使用率超过 80% 告警
avg by (host) (rate(cpu_usage_percent[5m])) > 80

# 任意实例 CPU 使用率超过 95% 告警(关注峰值)
max by (host) (rate(cpu_usage_percent[5m])) > 95

stddev 用于检测负载不均衡或异常波动:

# 各实例延迟标准差超过 200ms 时告警
stddev by (service) (http_request_duration_seconds) > 0.2
收敛策略:当 stddev 突然增大但 avg 变化不大时,说明部分实例出现异常,此时应触发“负载不均衡”告警,而非直接对平均值告警。

4.4 排序型操作符:topk、quantile_over_time

topk 用于返回数值最大的 K 个序列,适合在告警中定位“最差”的实例:

# 返回延迟最高的 5 个实例
topk(5, http_request_duration_seconds)

# 在告警规则中,topk 通常配合其他操作符使用
# 例如:对 topk 的实例单独告警
topk(3, max by (instance) (rate(http_errors_total[5m]))) > 10

quantile_over_time 是 聚合函数(非操作符),用于在时间窗口内计算分位数。它是构建 P99/P95 告警的核心工具:

# 计算过去 5 分钟的 P99 延迟
quantile_over_time(0.99, http_request_duration_seconds[5m])

# 在告警规则中使用
quantile_over_time(0.99, http_request_duration_seconds[5m]) > 1.0
性能注意:quantile_over_time 需要在内存中保留完整的时间窗口数据,窗口越大内存开销越高。建议生产环境窗口不超过 10 分钟,并配合 record 规则预计算。

4.5 聚合操作符与收敛规则组合

在告警收敛中,聚合操作符的嵌套使用可以显著减少告警风暴。下图展示了从原始指标到收敛告警的典型流程:

聚合操作符与告警收敛流程 原始指标 (instance 粒度) 聚合操作符 (sum/avg/max) 收敛规则 (for/group_interval) 告警 聚合操作符在收敛中的典型组合 场景 1:总量告警 + 收敛 sum by (service) (rate(http_errors_total[5m])) > 100 配合 for: 2m 避免瞬时抖动触发告警 场景 2:峰值告警 + 收敛 max by (instance) (rate(cpu_usage[5m])) > 90 配合 group_interval: 5m 避免重复告警 场景 3:分位数告警 + 收敛 quantile_over_time(0.99, http_duration_seconds[5m]) > 2.0 配合 record 规则预计算,降低 Prometheus 查询压力

4.6 聚合操作符选择矩阵

在实际告警规则编写中,选择合适的聚合操作符需要综合考虑指标类型、告警目标和收敛效果。下表给出了不同场景下的推荐选择:

告警目标 推荐操作符 收敛配合 示例表达式
检测服务整体健康度 avg for: 3m avg by (service) (up) < 0.8
检测单实例异常 max / topk for: 1m max by (instance) (error_rate) > 5
检测负载不均衡 stddev for: 5m stddev by (service) (cpu_usage) > 20
检测延迟毛刺 quantile_over_time record 预计算 quantile_over_time(0.99, latency[5m]) > 1.0
检测实例数不足 count for: 2m count by (service) (up) < 3

4.7 实战:编写一个多维度聚合告警规则

以下是一个完整的告警规则示例,综合使用了 sum、avg、quantile_over_time 和收敛参数:

groups:
  - name: api_latency_alerts
    rules:
      # 规则1:P99 延迟超过 2s 告警(预计算)
      - record: job:api:p99_latency:5m
        expr: quantile_over_time(0.99, api_request_duration_seconds[5m])
      - alert: HighP99Latency
        expr: job:api:p99_latency:5m > 2.0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "API P99 latency high ({{ $value }}s)"

      # 规则2:平均延迟超过 1s 告警(聚合收敛)
      - alert: HighAvgLatency
        expr: avg by (service) (rate(api_request_duration_seconds_sum[5m]) / rate(api_request_duration_seconds_count[5m])) > 1.0
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "Service {{ $labels.service }} avg latency high"

      # 规则3:单实例延迟异常(topk 定位)
      - alert: InstanceLatencySpike
        expr: topk(3, max by (instance) (api_request_duration_seconds)) > 3.0
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "Instance {{ $labels.instance }} latency spike"
关键点:
  • 使用 record 规则预计算 quantile_over_time,避免每次告警评估都重新计算。
  • 不同严重级别使用不同的 for 时长:critical 用 2m,warning 用 3m,减少误告警。
  • topk 只返回 Top 3 实例,避免告警风暴。

4.8 常见错误与排查方法

聚合操作符使用不当是告警误报和漏报的主要原因。下表列出了 5 个常见错误及对应的排查方法:

错误现象 可能原因 排查方法
告警值远高于预期 sum 未使用 by 子句,聚合了所有维度 在 Prometheus UI 中执行 sum(metric) 查看原始值
告警频繁触发/解除 使用了 min 或 max 但未加 for 收敛 增加 for: 2m 或改用 avg
P99 告警不准确 quantile_over_time 窗口过短 将窗口从 1m 调整为 5m 或 10m
topk 告警无输出 topk 返回的是序列,不是标量 配合 max 或 avg 转换为标量再比较
stddev 告警无意义 指标本身波动大,stddev 天然高 改用 stddev / avg 计算变异系数
核心原则:聚合操作符的选择直接影响告警的准确性和收敛效果。在编写告警规则前,务必在 Prometheus UI 中先用 sum、avg、topk 等操作符预览数据分布,确认聚合后的数值符合预期后再写入规则文件。