3. SLI 指标设计:如何为不同服务定义有效的 SLI 指标
SLI(Service Level Indicator)是 SLO 体系的基石。没有精确、可采集的 SLI,SLO 就是空中楼阁。本章聚焦于如何为不同服务类型定义有效的 SLI 指标,覆盖延迟、错误率、吞吐量、饱和度四个黄金信号,并提供从理论到落地的完整设计方法。
核心原则:SLI 必须满足“可测量、可对比、可告警”三要素。每个 SLI 都应明确采集窗口、聚合方式与良好事件判定标准。
3.1 四大黄金信号与 SLI 映射
Google SRE 经典理论将服务监控指标归纳为四个黄金信号。每个信号对应一类典型的 SLI 定义方式:
| 黄金信号 | 典型 SLI 定义 | 适用场景 | 常见采集粒度 |
|---|---|---|---|
| 延迟 | 请求在指定阈值内完成的百分比 | API、数据库、缓存、RPC 调用 | p50/p95/p99,窗口 1min-5min |
| 错误率 | 请求返回非成功状态码的占比 | HTTP 服务、gRPC、消息队列消费 | 5xx 占比、业务错误码占比 |
| 吞吐量 | 单位时间内成功处理的请求量 | 网关、批处理、流处理系统 | QPS、TPS、RPS |
| 饱和度 | 资源使用量占总容量的比例 | CPU、内存、磁盘、连接池、队列深度 | 利用率百分比、队列长度 |
设计提示:不要试图为每个信号都定义 SLI。优先选择与用户体验最直接相关的 1-2 个信号。例如,用户侧 API 优先关注延迟和错误率;后台批处理优先关注吞吐量和饱和度。
3.2 延迟 SLI:从分布到阈值
延迟 SLI 的核心是“在给定时间窗口内,请求延迟低于目标阈值的比例”。定义时需明确三个参数:
- 采集窗口:通常为 1 分钟或 5 分钟滑动窗口,避免毛刺导致误告警。
- 聚合方式:推荐使用百分位数(p50/p95/p99),而非平均值。平均值会掩盖长尾延迟。
- 良好事件判定:延迟 ≤ 阈值(如 p99 ≤ 200ms)视为一次良好事件。
# 延迟 SLI 示例(PromQL 风格)
# 计算过去 5 分钟内,p99 延迟 ≤ 200ms 的请求占比
(
sum(rate(http_request_duration_seconds_bucket{le="0.2"}[5m]))
/
sum(rate(http_request_duration_seconds_count[5m]))
) * 100
常见陷阱:仅使用 p50 作为延迟 SLI 会导致大量慢请求被忽略。建议至少同时跟踪 p95 和 p99,并针对 p99 设置告警阈值。
3.3 错误率 SLI:区分显式与隐式错误
错误率 SLI 定义为“错误请求数 / 总请求数 × 100%”。但“错误”的定义需要精细设计:
| 错误类型 | 示例 | 是否计入 SLI | 说明 |
|---|---|---|---|
| HTTP 5xx | 500 Internal Server Error | 是 | 服务端故障,直接影响用户 |
| HTTP 4xx | 404 Not Found | 否(通常) | 客户端错误,非服务责任 |
| 业务错误码 | 订单超时、库存不足 | 视情况 | 需业务方定义“可接受错误” |
| 超时/熔断 | 上游调用超时 | 是 | 属于服务能力不足 |
# 错误率 SLI 示例(仅计算 5xx)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
最佳实践:对于业务服务,建议定义“有效错误率”——排除已知的客户端错误(如 4xx)和计划内的业务拒绝(如限流返回 429),只统计真正反映服务健康度的错误。
3.4 吞吐量 SLI:容量与负载的平衡
吞吐量 SLI 通常定义为“单位时间内成功处理的请求数”。它本身不直接反映服务质量,但结合延迟和错误率可以判断服务是否过载。
- 吞吐量:QPS / TPS,用于衡量系统处理能力。
- 相对吞吐量:当前吞吐量 / 历史峰值吞吐量,用于判断是否接近容量上限。
- 吞吐量异常:当吞吐量突然下降 50% 以上时,通常意味着服务故障或上游限流。
设计建议:吞吐量 SLI 更适合作为“辅助指标”而非核心 SLO。例如,当吞吐量下降且错误率上升时,触发告警自愈流程。
3.5 饱和度 SLI:资源瓶颈的早期预警
饱和度 SLI 关注资源使用量占总容量的比例。它是四个信号中唯一一个“预测性”指标,能在故障发生前发出预警。
| 资源类型 | 典型 SLI 定义 | 告警阈值建议 | 说明 |
|---|---|---|---|
| CPU | CPU 利用率(1min 平均) | ≥ 80% | 超过 80% 可能引发延迟抖动 |
| 内存 | 内存使用率 | ≥ 85% | 接近 OOM 风险 |
| 磁盘 I/O | 磁盘队列深度 / 最大队列深度 | ≥ 70% | I/O 等待时间会急剧上升 |
| 连接池 | 活跃连接数 / 最大连接数 | ≥ 80% | 新连接可能被阻塞 |
| 消息队列 | 队列积压消息数 | ≥ 1000(视业务定) | 消费能力不足 |
# 饱和度 SLI 示例(CPU 利用率)
avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))
# 转换为利用率:1 - 上述值
3.6 SLI 设计流程:从服务类型到指标定义
不同服务类型需要不同的 SLI 设计策略。以下是一个通用的四步设计流程:
- 识别用户旅程:确定服务对外提供的核心功能(如“用户登录”、“商品搜索”)。
- 选择黄金信号:根据服务类型选择 1-2 个最相关的信号(如 API 选延迟+错误率,缓存选延迟+饱和度)。
- 定义良好事件:明确“什么算一次好的请求”(如 p99 延迟 ≤ 200ms 且状态码 200)。
- 设定采集与聚合:确定指标来源(APM、Exporter、业务埋点)、窗口大小、百分位选择。
3.7 不同服务类型的 SLI 设计模板
以下模板可直接用于常见服务类型的 SLI 定义:
| 服务类型 | 推荐 SLI | 良好事件定义 | 采集方式 |
|---|---|---|---|
| HTTP API 网关 | 延迟 + 错误率 | p99 ≤ 300ms 且 5xx 占比 ≤ 0.5% | APM 或反向代理日志 |
| 数据库(MySQL/Redis) | 延迟 + 饱和度 | p99 查询延迟 ≤ 50ms,连接数 ≤ 80% | 数据库 Exporter |
| 消息队列(Kafka/RabbitMQ) | 吞吐量 + 饱和度 | 消费速率 ≥ 生产速率 90%,队列积压 ≤ 1000 | MQ Exporter + 业务埋点 |
| 批处理任务 | 吞吐量 + 错误率 | 任务完成率 ≥ 99%,失败重试次数 ≤ 3 | 任务调度系统指标 |
| CDN / 静态资源 | 延迟 + 错误率 | 全球 p95 延迟 ≤ 100ms,命中率 ≥ 95% | CDN 厂商 API |
快速上手:如果团队刚开始建设 SLI,建议从“HTTP API 延迟 + 错误率”开始,这是最容易采集且与用户体验最直接相关的指标。后续再逐步扩展到基础设施饱和度。
3.8 SLI 与 SLO 的衔接:从指标到目标
定义好 SLI 后,下一步是设定 SLO 目标值。SLI 是“测量值”,SLO 是“目标值”。例如:
- SLI:过去 5 分钟内,p99 延迟 ≤ 200ms 的请求占比。
- SLO:该占比 ≥ 99.9%(即每月允许的坏事件窗口约 43 分钟)。
SLI 的采集窗口和聚合方式直接影响 SLO 的达成判断。建议在定义 SLI 时就明确:
- 窗口大小:推荐 5 分钟滑动窗口,平衡灵敏度与稳定性。
- 百分位选择:核心服务用 p99,非核心服务可用 p95。
- 排除策略:是否排除计划内维护、客户端错误等。
关键提醒:SLI 定义完成后,必须经过“可采集性验证”——确认指标能从现有监控系统(Prometheus、Datadog、SkyWalking 等)中稳定获取。如果无法采集,再完美的 SLI 定义也是无效的。