3. SLI 采集与指标设计:如何定义有效的 SLI 指标,基于 RED 方法设计黄金信号
在可观测性体系中,SLI(Service Level Indicator,服务等级指标)是连接原始观测数据与 SLO 违约判定的桥梁。如果 SLI 定义不准确,后续的告警、追踪与 MTTR 复盘将失去根基。本章聚焦于如何基于 RED 方法(Rate、Errors、Duration) 设计黄金信号,确保每个 SLI 都能真实反映用户侧的服务质量。
3.1 为什么选择 RED 方法?
传统监控常陷入“指标爆炸”的困境——CPU、内存、磁盘、网络等基础设施指标堆积如山,却无法回答“服务是否正常”这一核心问题。RED 方法由 Tom Wilkie 提出,专为微服务与分布式系统设计,将指标收敛为三个维度:
| 维度 | 英文 | 核心含义 | 典型问题 |
|---|---|---|---|
| Rate(速率) | Rate | 每秒请求数(RPS)或每分钟事务数 | 流量是否正常?是否存在突发或断崖? |
| Errors(错误) | Errors | 请求失败的数量或比例 | 错误率是否超过阈值?哪些接口在报错? |
| Duration(持续时间) | Duration | 请求响应时间(延迟分布) | P50/P95/P99 延迟是否满足预期? |
关键原则:RED 方法要求每个服务至少暴露 Rate、Errors、Duration 三个指标,且指标必须从用户请求的视角采集,而非从基础设施视角。
3.2 基于 RED 方法的 SLI 定义框架
定义 SLI 时,需要明确 指标名称、测量方式、聚合粒度 和 时间窗口。以下是一个标准化的 SLI 定义模板:
# 通用 SLI 定义模板
sli_name: "service_requests_total"
type: counter
labels:
- service: "checkout-service"
- endpoint: "/api/v1/checkout"
- method: "POST"
- status_code: "2xx|4xx|5xx"
measurement: "每秒请求数(RPS)"
aggregation: "1分钟窗口平均"
针对 RED 三个维度,我们分别给出具体的 SLI 设计示例:
3.2.1 Rate(速率)SLI
- 指标名:
http_requests_total(Counter 类型) - 标签:
service、endpoint、method - 计算方式:
rate(http_requests_total[1m]) - 用途:检测流量异常(如突降表示服务不可用,突增表示可能遭受攻击或促销活动)
3.2.2 Errors(错误)SLI
- 指标名:
http_requests_errors_total(Counter 类型) - 标签:
service、endpoint、error_code(如 500、503、timeout) - 计算方式:
rate(http_requests_errors_total[1m]) / rate(http_requests_total[1m]) - 用途:计算错误率,触发 SLO 违约告警的核心依据
3.2.3 Duration(持续时间)SLI
- 指标名:
http_request_duration_seconds(Histogram 类型) - 标签:
service、endpoint、le(桶边界) - 计算方式:
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) - 用途:获取 P99 延迟,判断长尾请求是否影响用户体验
实践建议:Duration 指标推荐使用 Histogram 而非 Summary。Histogram 支持服务端聚合与分位数计算,更适合分布式追踪场景下的全局延迟分析。
3.3 RED 黄金信号与分布式追踪的映射
在分布式追踪中,每个 Span 都携带了 RED 所需的信息。通过 OpenTelemetry 或 Jaeger 等工具,我们可以直接从 Trace 中提取 SLI:
| RED 维度 | Trace 字段 | 采集方式 |
|---|---|---|
| Rate | span_id 计数 |
统计每秒产生的 Root Span 数量 |
| Errors | status.code |
统计 status.code = ERROR 的 Span 占比 |
| Duration | end_time - start_time |
对 Span 持续时间进行分位数计算 |
下图展示了从 Trace 到 SLI 再到 SLO 的完整数据流:
3.4 SLI 设计中的常见陷阱与避坑指南
陷阱 1:使用平均值衡量 Duration。 平均延迟会掩盖长尾问题。例如 99% 请求 10ms,1% 请求 10s,平均值为 109ms,看似正常,实则 P99 已严重超标。正确做法:始终使用分位数(P50/P95/P99)。
陷阱 2:错误率只统计 HTTP 5xx。 业务错误(如“库存不足”返回 200)同样影响用户体验。正确做法:在应用层定义业务错误码,并纳入 Errors SLI。
陷阱 3:Rate 指标忽略健康检查流量。 健康检查请求会拉高 Rate,稀释真实用户流量。正确做法:通过标签过滤掉
/health、/metrics 等端点。
3.5 实战:为“订单服务”定义 RED 黄金信号
假设我们有一个 order-service,需要为其定义 SLI。以下是完整的指标设计清单:
| SLI 名称 | 类型 | PromQL 示例 | SLO 目标 |
|---|---|---|---|
order_requests_rate |
Rate | rate(order_requests_total[1m]) |
≥ 100 RPS(基线) |
order_error_ratio |
Errors | rate(order_errors_total[1m]) / rate(order_requests_total[1m]) |
≤ 0.1% |
order_duration_p99 |
Duration | histogram_quantile(0.99, rate(order_duration_seconds_bucket[5m])) |
≤ 500ms |
采集配置示例(OpenTelemetry Collector):
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
attributes:
actions:
- key: service.name
value: "order-service"
action: upsert
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
namespace: "sre"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, attributes]
exporters: [prometheus]
通过上述配置,Trace 数据中的 Span 持续时间、状态码等信息会被自动转换为 Prometheus 指标,进而支持 RED 黄金信号的实时计算。
3.6 小结:SLI 设计的三个黄金法则
- 用户视角优先:SLI 必须从用户请求的入口开始采集,而非从中间件或基础设施。
- RED 全覆盖:每个服务至少暴露 Rate、Errors、Duration 三类指标,缺一不可。
- 分位数与窗口:Duration 使用 P99/P95,错误率使用滑动窗口(如 5 分钟),避免瞬时抖动导致误告警。