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 违约率:

四大黄金信号采集与 SLI 计算流程 四大黄金信号 → SLI 计算流程 延迟采集 流量采集 错误采集 饱和度采集 SLI 聚合计算(窗口滑动 / 时间桶) SLO 违约率计算 → 告警触发 说明:每个信号独立计算 SLI,再按 SLO 目标加权汇总违约率。饱和度通常作为告警前置条件,不直接参与 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 组合:

SLI 适配决策树 SLI 适配决策树 服务类型是什么? 同步服务(API/DB) 延迟:p99 延迟 错误:HTTP 5xx / 超时 异步服务(MQ/流处理) 延迟:端到端投递延迟 错误:重试/死信率 饱和度:CPU/内存/连接池 说明:流量 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 违约率体系。