3. Prometheus SLI 采集:核心指标采集实战
SLI(Service Level Indicator)是 SLO 的量化基础。本章聚焦于如何使用 Prometheus 采集请求总数、成功数、延迟分布等核心 SLI 指标,确保数据源准确、完整、可审计。采集质量直接决定误差预算台账的可靠性。
3.1 SLI 指标分类与采集策略
根据 Google SRE 经典模型,SLI 通常分为三类:吞吐量(请求总数)、成功率(成功请求占比)、延迟(响应时间分布)。每类指标在 Prometheus 中的采集方式不同,需根据应用协议(HTTP/gRPC/自定义)选择对应 Exporter 或埋点方案。
| SLI 类别 | 核心指标 | Prometheus 指标类型 | 典型采集方式 |
|---|---|---|---|
| 吞吐量 | 请求总数 | Counter | HTTP 请求计数器(http_requests_total) |
| 成功率 | 成功请求数 / 错误请求数 | Counter | 按状态码分类的计数器(http_requests_total{status="2xx"}) |
| 延迟 | P50 / P90 / P99 延迟 | Histogram / Summary | 请求耗时直方图(http_request_duration_seconds) |
采集原则:所有 SLI 指标必须携带足够的标签维度(如
service、endpoint、method),以便后续按 SLO 边界进行聚合和筛选。标签基数需控制在合理范围内,避免 Prometheus 存储爆炸。
3.2 请求总数与成功数采集:Counter 模式
请求总数和成功数通常使用 Counter 类型指标。Counter 只增不减,适合累计计数场景。以下是一个基于 Prometheus 客户端库(Go 示例)的埋点代码片段:
// 定义计数器
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"service", "endpoint", "method", "status_class"},
)
)
// 在请求处理中间件中记录
func MetricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 请求进入时增加总数
httpRequestsTotal.With(prometheus.Labels{
"service": "user-service",
"endpoint": r.URL.Path,
"method": r.Method,
"status_class": "total",
}).Inc()
// 包装 ResponseWriter 以捕获状态码
wrapped := &responseWriter{ResponseWriter: w, statusCode: 200}
next.ServeHTTP(wrapped, r)
// 根据状态码分类增加成功/失败计数
statusClass := classifyStatus(wrapped.statusCode)
httpRequestsTotal.With(prometheus.Labels{
"service": "user-service",
"endpoint": r.URL.Path,
"method": r.Method,
"status_class": statusClass,
}).Inc()
})
}
func classifyStatus(code int) string {
if code < 500 {
return "success" // 2xx, 3xx, 4xx 视为成功(根据 SLO 定义调整)
}
return "error"
}
关键点:成功/失败的分类逻辑必须与 SLO 定义一致。例如,某些服务将 4xx 视为成功(客户端错误),而将 5xx 视为失败。务必在采集层明确分类规则,并在 Prometheus 标签中体现。
3.3 延迟采集:Histogram 与 Summary 选择
延迟是 SLI 中最复杂的指标。Prometheus 提供两种方式:Histogram(直方图)和 Summary(摘要)。两者都能计算分位数,但适用场景不同。
| 特性 | Histogram | Summary |
|---|---|---|
| 分位数计算位置 | 查询端(PromQL 计算) | 客户端(Exporter 预计算) |
| 聚合能力 | 支持跨实例聚合(histogram_quantile) |
不支持聚合 |
| 存储开销 | 较高(需定义 bucket 边界) | 较低(只输出预计算分位数) |
| 推荐场景 | 需要全局 P99 延迟、多维度聚合 | 单实例、无需聚合的延迟监控 |
对于 SLO 误差预算计算,推荐使用 Histogram,因为需要跨多个实例聚合全局延迟分布。以下是 Histogram 埋点示例:
// 定义直方图,bucket 边界覆盖目标延迟范围
var (
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request latency in seconds.",
Buckets: prometheus.DefBuckets, // 默认: .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10
},
[]string{"service", "endpoint"},
)
)
// 在请求处理中间件中记录耗时
func LatencyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start).Seconds()
httpRequestDuration.With(prometheus.Labels{
"service": "user-service",
"endpoint": r.URL.Path,
}).Observe(duration)
})
}
Bucket 边界设计:Bucket 必须覆盖 SLO 目标延迟。例如,若 SLO 要求 99% 请求在 500ms 内完成,则 bucket 应包含 0.5 边界,并在 0.5 附近有足够密度。建议使用
exponentialBuckets(0.001, 2, 15) 生成指数分布 bucket。
3.4 SLI 采集架构与数据流
下图展示了从应用埋点到 Prometheus 存储的完整 SLI 数据流,包含多服务、多实例的采集拓扑:
3.5 多协议 SLI 采集方案对比
不同协议的服务需要不同的采集方案。以下表格总结了常见协议的 SLI 采集方式:
| 协议 | 推荐 Exporter / 库 | 核心指标 | 注意事项 |
|---|---|---|---|
| HTTP (REST) | Prometheus 客户端库 / Nginx Exporter | http_requests_total, http_request_duration_seconds |
注意 4xx/5xx 分类逻辑 |
| gRPC | gRPC Prometheus 拦截器 | grpc_server_handling_seconds, grpc_server_started_total |
gRPC 状态码映射到 success/error |
| 自定义 TCP | 自定义 Exporter / Textfile Collector | 业务自定义 Counter / Gauge | 需自行实现指标暴露端点 |
| 消息队列 | Kafka Exporter / RabbitMQ Exporter | kafka_consumer_lag, rabbitmq_queue_messages |
延迟指标需从消费端采集 |
3.6 采集质量验证与常见陷阱
SLI 采集完成后,必须进行质量验证,避免“垃圾进垃圾出”。以下是验证清单和常见陷阱:
- 指标命名一致性:所有服务使用统一的指标命名规范(如
http_requests_total),避免大小写、下划线不一致。 - 标签基数控制:避免将用户 ID、请求 ID 等高基数标签加入 SLI 指标,会导致 Prometheus 内存飙升。
- Counter 重置检测:使用
rate()函数时,确保 Counter 在服务重启后正确重置,避免计算错误。 - Histogram 桶溢出:如果请求延迟超过最大 bucket 边界,会落入
+Inf桶,导致分位数计算偏差。需定期检查+Inf桶计数。 - 采集延迟:Prometheus 拉取间隔(默认 15s)与 SLO 评估窗口(如 30 天)相比可忽略,但高精度延迟分析需考虑 scrape 抖动。
验证命令:在 Prometheus 中执行以下查询,检查指标是否正常采集:
count by (service) (http_requests_total) — 查看各服务是否有数据histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) — 验证 P99 延迟计算