2. SLI 指标设计:四大黄金信号与不同服务的适配策略
SLI(Service Level Indicator)是 SLO 体系的基石。Google SRE 实践总结出“四大黄金信号”——延迟、流量、错误、饱和度,但并非所有服务都适用同一套指标。本章将拆解每个信号的定义、采集方式,并给出不同服务类型(API、数据库、消息队列、CDN)的 SLI 适配方案。
2.1 四大黄金信号定义与采集
| 信号 | 核心含义 | 典型采集方式 | 常见单位 |
|---|---|---|---|
| 延迟 | 请求从发出到收到响应的时间 | 服务端埋点(p50/p90/p99)、APM 探针 | ms |
| 流量 | 系统承载的请求量或吞吐量 | 负载均衡器日志、服务端计数器 | RPS、QPS、TPS、带宽 |
| 错误 | 请求失败的比例(HTTP 5xx、超时、业务错误码) | HTTP 状态码统计、业务日志告警 | 百分比、错误率 |
| 饱和度 | 资源使用程度(CPU、内存、磁盘、连接池) | 系统指标采集(Prometheus Node Exporter、JMX) | 百分比、剩余容量 |
关键原则:SLI 必须可测量、可对比、可告警。避免使用“平均延迟”作为 SLI,推荐使用高百分位(p99)来捕捉长尾问题。
2.2 不同服务类型的 SLI 适配方案
同一套黄金信号在不同服务中权重不同。以下表格给出四种典型服务的 SLI 推荐组合:
| 服务类型 | 延迟 SLI | 流量 SLI | 错误 SLI | 饱和度 SLI |
|---|---|---|---|---|
| API 网关 | p99 延迟 ≤ 200ms | QPS 峰值 ≤ 容量 80% | HTTP 5xx 率 ≤ 0.1% | CPU 使用率 ≤ 70% |
| 数据库(MySQL) | p99 查询延迟 ≤ 50ms | TPS 峰值 ≤ 容量 70% | 慢查询占比 ≤ 1% | 连接数使用率 ≤ 80% |
| 消息队列(Kafka) | 端到端投递延迟 ≤ 500ms | 消息堆积量 ≤ 阈值 | 重试/死信率 ≤ 0.5% | 磁盘使用率 ≤ 85% |
| CDN 边缘节点 | 首字节时间 ≤ 100ms | 带宽使用率 ≤ 90% | 回源率 ≤ 5% | 缓存命中率 ≥ 95% |
实战提示:定义 SLI 时,优先选择“用户可感知”的指标。例如 API 网关的延迟 SLI 应基于客户端到网关的端到端延迟,而非仅服务端处理时间。
2.3 四大黄金信号关联流程(SVG)
下图展示四大黄金信号如何从采集层汇聚到 SLI 计算层,最终输出 SLO 违约率:
2.4 饱和度:被低估的“前哨”信号
饱和度是四大信号中唯一不直接反映用户请求质量的指标,但它是系统崩溃的“前哨”。当资源使用率超过 80% 时,延迟和错误率往往开始非线性恶化。
- CPU 饱和度:使用率 > 80% 时,上下文切换开销剧增,p99 延迟可能翻倍。
- 内存饱和度:剩余内存 < 10% 时,OOM Killer 风险上升,建议设置内存使用率 SLI 为 ≤ 85%。
- 连接池饱和度:数据库连接池使用率 > 70% 时,新请求排队等待,延迟飙升。
- 磁盘 I/O 饱和度:磁盘队列深度持续 > 2 时,I/O 延迟显著增加。
避坑指南:不要将饱和度 SLI 直接纳入 SLO 违约率计算(否则资源扩容会频繁触发告警)。建议将饱和度作为“告警前置条件”——当饱和度超过阈值时,自动触发扩容流程,而非直接判定 SLO 违约。
2.5 错误信号:区分“真错误”与“假错误”
错误 SLI 的设计最容易出现误判。以下表格列出常见错误分类及处理建议:
| 错误类型 | 示例 | 是否计入 SLI | 处理方式 |
|---|---|---|---|
| HTTP 5xx | 500 Internal Server Error | 是 | 直接计入错误率 |
| HTTP 4xx(客户端) | 404 Not Found | 否 | 排除,属于客户端问题 |
| 业务错误码 | 订单超时、库存不足 | 视情况 | 仅当业务定义“失败”时计入 |
| 超时重试 | 客户端重试后成功 | 否 | 以最终结果为准,避免重复计数 |
| 健康检查请求 | K8s liveness probe | 否 | 从 SLI 计算中过滤掉 |
2.6 流量信号:容量规划的“晴雨表”
流量 SLI 通常不直接用于 SLO 违约率计算,但它是容量规划和限流降级的关键输入。推荐做法:
- 设置流量上限 SLI:例如“QPS 峰值不超过容量的 80%”,超过时触发扩容或限流。
- 流量异常检测:使用同比/环比算法(如 Prometheus 的
predict_linear)预测流量趋势,提前扩容。 - 流量与延迟联动:当流量增长 20% 且延迟增长超过 10% 时,触发告警。
实战案例:某电商 API 网关定义流量 SLI 为“每秒请求数 ≤ 5000”,当流量超过 4000 时自动触发限流,避免后端数据库被突发流量打垮。该 SLI 不参与 SLO 违约率计算,但作为独立告警规则运行。
2.7 延迟信号:高百分位 vs 平均值
延迟 SLI 是用户感知最直接的指标。以下对比不同百分位的适用场景:
| 百分位 | 含义 | 适用场景 | 典型阈值 |
|---|---|---|---|
| p50(中位数) | 50% 的请求快于该值 | 整体性能基线监控 | ≤ 100ms |
| p90 | 90% 的请求快于该值 | 一般用户体验监控 | ≤ 300ms |
| p99 | 99% 的请求快于该值 | SLO 核心指标,捕捉长尾 | ≤ 500ms |
| p99.9 | 99.9% 的请求快于该值 | 高 SLA 服务(金融、实时系统) | ≤ 1s |
推荐:对于大多数 Web 服务,使用 p99 延迟作为 SLI 即可。p99.9 需要大量样本数据支撑,且容易受极端噪声影响,建议仅在核心链路使用。
2.8 不同服务 SLI 适配决策树(SVG)
以下决策树帮助 SRE 快速为任意服务选择 SLI 组合:
2.9 实战:为微服务定义 SLI 清单
以下是一个微服务 SLI 定义的完整示例(YAML 格式),可直接用于 Prometheus + Alertmanager 配置:
# 用户服务 SLI 定义
slis:
- name: "user-api-latency-p99"
type: latency
metric: "http_request_duration_seconds{service='user-api'}"
aggregation: "histogram_quantile(0.99, ...)"
threshold: 0.5 # 500ms
window: "5m"
- name: "user-api-error-rate"
type: error
metric: "http_requests_total{service='user-api', status=~'5..'}"
aggregation: "rate(...)[5m]"
threshold: 0.001 # 0.1%
window: "5m"
- name: "user-api-cpu-saturation"
type: saturation
metric: "node_cpu_usage_ratio{service='user-api'}"
aggregation: "avg(...)[5m]"
threshold: 0.8 # 80%
window: "5m"
alert_only: true # 不参与 SLO 违约率计算
关键点:每个 SLI 必须明确
aggregation(聚合方式)、threshold(阈值)、window(时间窗口)。饱和度 SLI 设置 alert_only: true 避免干扰 SLO 违约率计算。
2.10 本章小结
- 四大黄金信号(延迟、流量、错误、饱和度)是 SLI 设计的通用框架,但需根据服务类型调整权重。
- 延迟 SLI 优先使用 p99 百分位,避免平均值掩盖长尾问题。
- 错误 SLI 必须过滤健康检查、客户端错误和重试成功请求。
- 饱和度 SLI 作为告警前置条件,不直接参与 SLO 违约率计算。
- 流量 SLI 用于容量规划和限流触发,独立于 SLO 违约率体系。