4. PromQL 编写 SLI:使用 histogram_quantile 计算延迟分位数,rate 计算错误率
SLI(Service Level Indicator)是 SLO 的量化基石。在 Prometheus 生态中,延迟和错误是最核心的两个黄金信号。本章将聚焦如何用 PromQL 精确编写这两类 SLI,并确保查询在性能与语义上均符合生产标准。
4.1 延迟分位数 SLI:histogram_quantile
延迟通常以 Histogram 类型采集,PromQL 通过 histogram_quantile(φ, scalar, instant-vector) 计算指定分位数的近似值。典型场景:99% 的请求在 200ms 内完成。
4.1.1 标准查询模板
# 计算过去 5 分钟所有请求的 p99 延迟(秒)
histogram_quantile(0.99,
sum by (le) (
rate(http_request_duration_seconds_bucket[5m])
)
)
关键点:
rate(...[5m])将累积计数器转换为每秒速率,消除重启与时间窗口影响。sum by (le)按桶边界聚合,确保多实例数据正确合并。- 分位数 φ 必须介于 0 ~ 1 之间,常用 0.5、0.9、0.99、0.999。
4.1.2 多维度分位数(按服务/端点拆分)
# 按 service 和 endpoint 维度计算 p99 延迟
histogram_quantile(0.99,
sum by (le, service, endpoint) (
rate(http_request_duration_seconds_bucket[5m])
)
)
| 维度 | 说明 | 典型值 |
|---|---|---|
service |
微服务名称 | api-gateway, user-svc |
endpoint |
API 路径或 RPC 方法 | /v1/orders, GetUser |
le |
Histogram 桶上界(必须保留) | 0.1, 0.5, 1.0, +Inf |
⚠ 性能陷阱: 避免在
histogram_quantile 内使用 avg 或 max 聚合桶数据,这会导致分位数计算失真。始终使用 sum by (le, ...) 保持桶结构完整。
4.2 错误率 SLI:rate
错误率定义为 错误请求数 / 总请求数。Prometheus 通常使用两个 Counter 指标:http_requests_total(总请求)和 http_requests_total{status=~"5.."}(错误请求)。
4.2.1 标准错误率查询
# 过去 5 分钟的错误率(百分比)
(
sum by (service) (
rate(http_requests_total{status=~"5[0-9][0-9]"}[5m])
)
/
sum by (service) (
rate(http_requests_total[5m])
)
) * 100
💡 最佳实践: 使用
status=~"5.." 正则匹配 5xx 状态码,而非硬编码每个错误码。对于 gRPC,使用 grpc_code=~"^[2-9].." 匹配非 OK 状态。
4.2.2 排除健康检查与低流量时段
# 排除 /health 端点,避免稀释错误率
(
sum by (service) (
rate(http_requests_total{status=~"5[0-9][0-9]", endpoint!="/health"}[5m])
)
/
sum by (service) (
rate(http_requests_total{endpoint!="/health"}[5m])
)
) * 100
4.3 延迟与错误率 SLI 的 PromQL 结构对比
| SLI 类型 | 核心函数 | 聚合方式 | 典型时间窗口 | 输出单位 |
|---|---|---|---|---|
| 延迟分位数 | histogram_quantile |
sum by (le, ...) |
5m / 10m | 秒(s) |
| 错误率 | rate |
sum by (...) |
5m / 1m | 百分比(%) |
4.4 延迟分位数计算流程(SVG)
4.5 错误率计算流程(SVG)
4.6 常见错误与调优建议
- 桶数量不足: 如果 Histogram 桶少于 10 个,
histogram_quantile插值误差会显著增大。建议至少配置 15~20 个桶,覆盖预期延迟范围。 - 时间窗口过短:
rate(...[1m])在低流量服务中容易抖动,推荐使用[5m]或[10m]作为 SLI 窗口。 - 未排除零值桶: 如果
+Inf桶速率异常高,说明桶上界设置过小,应扩展最大桶值。 - 错误率分母为 0: 当窗口内无请求时,除法返回 NaN。建议使用
or vector(0)兜底:(... / ...) or vector(0)。
✅ 生产级 SLI 查询示例(完整版):
# p99 延迟 SLI
histogram_quantile(0.99,
sum by (le, service) (
rate(http_request_duration_seconds_bucket[5m])
)
)
# 错误率 SLI(含 NaN 保护)
(
sum by (service) (
rate(http_requests_total{status=~"5[0-9][0-9]"}[5m])
)
/
sum by (service) (
rate(http_requests_total[5m])
)
or vector(0)
) * 100