SLI 设计原则:如何选择合适的服务等级指标
服务等级指标(SLI)是 SLO 体系的基石——没有正确的 SLI,任何 SLO 承诺都缺乏可测量、可验证的基础。SLI 设计不是简单地从监控系统中挑几个现成指标,而是需要根据服务架构、用户行为和业务目标进行结构化推导。本章围绕 SLI 的选取原则与黄金信号展开,帮助你在实际工程中做出可落地的指标决策。
2.1 SLI 选取的核心原则
好的 SLI 必须同时满足以下四个条件,缺一不可:
| 原则 | 说明 | 反例 |
|---|---|---|
| 用户可感知 | 指标必须反映用户实际体验,而非内部实现细节 | CPU 使用率、磁盘 IOPS |
| 可测量 | 指标必须能被精确采集,且采集开销可控 | "用户满意度"(无量化手段) |
| 可区分好坏 | 指标必须有明确的"好/坏"判定边界 | 仅报告平均延迟(掩盖长尾) |
| 可行动作 | 指标恶化时,团队能定位根因并采取修复措施 | "全局错误数"(无法区分模块) |
设计检查清单:每定义一个 SLI,问自己三个问题——(1) 这个指标下降时用户会投诉吗?(2) 我们能从现有遥测管道中直接计算它吗?(3) 它的"好"阈值是否与业务容忍度对齐?
2.2 黄金信号详解
Google SRE 团队提出的四个黄金信号(延迟、流量、错误、饱和度)是 SLI 设计的通用框架。它们覆盖了用户可感知的绝大部分维度,且彼此正交,避免指标冗余。下面逐一拆解每个信号的设计要点与常见陷阱。
2.2.1 延迟(Latency)
延迟衡量请求从发出到收到完整响应的时间。设计延迟 SLI 时,分布比均值更重要:
- 使用百分位数而非平均值:P50 反映典型体验,P95/P99 反映长尾体验。一个服务 P50=10ms 但 P99=5s,对 1% 的用户来说体验极差。
- 区分成功与失败请求的延迟:失败的快速响应不应计入延迟 SLI,否则会稀释真实数据。
- 定义"好延迟"阈值:例如"所有请求的 P99 延迟 ≤ 200ms"作为 SLI 的好事件判定条件。
2.2.2 流量(Traffic)
流量衡量系统承载的请求量级。流量 SLI 通常不直接用于 SLO 目标,而是作为饱和度与容量规划的输入:
- 按请求类型拆分:读请求 vs 写请求、API 端点级别、用户维度。
- 关注峰值而非均值:均值流量可能掩盖突发尖峰导致的限流或超时。
- 与延迟/错误联合分析:流量突增伴随延迟升高,说明系统接近瓶颈。
2.2.3 错误(Errors)
错误 SLI 是最直观的用户体验指标,但定义"什么是错误"需要谨慎:
| 错误类型 | 示例 | 是否计入 SLI |
|---|---|---|
| 显式错误 | HTTP 5xx、gRPC UNAVAILABLE | 是 |
| 隐式错误 | HTTP 200 但返回"查询失败" | 是(需业务语义解析) |
| 客户端错误 | HTTP 4xx(参数错误) | 否(非服务责任) |
| 超时重试成功 | 客户端重试后得到正确响应 | 否(但应监控重试率) |
常见陷阱:仅监控 HTTP 状态码会遗漏大量"静默错误"。例如搜索服务返回 200 但结果为空,对用户而言就是错误。建议在应用层注入业务错误码,并与 OpenTelemetry 的 span 事件关联。
2.2.4 饱和度(Saturation)
饱和度衡量系统资源被消耗的程度。它是延迟和错误的前兆指标——饱和度升高往往先于用户体验恶化:
- 选择最受限的资源:CPU、内存、磁盘 I/O、网络带宽、数据库连接池、线程池。
- 使用利用率而非值:例如"CPU 利用率 > 80%"比"CPU 使用 4000m"更有意义。
- 饱和度 SLI 通常不直接用于 SLO,而是作为容量规划的触发条件。
2.3 黄金信号关系图
下图展示了四个黄金信号之间的因果与反馈关系,帮助理解它们如何协同工作:
2.4 从黄金信号到 SLI 定义模板
将黄金信号转化为可执行的 SLI 定义,建议使用以下结构化模板:
SLI 名称:API 读取延迟
信号类型:延迟
测量对象:所有 HTTP GET /api/v1/books 请求
好事件定义:服务端处理时间(server_timing)≤ 200ms
测量窗口:滚动 5 分钟
数据来源:OpenTelemetry Span 属性 http.response_time
采集方式:Prometheus Histogram(bucket: 50ms, 100ms, 200ms, 500ms)
实践建议:每个服务至少定义 3 个 SLI——延迟(P99)、错误率(显式+隐式)、饱和度(最受限资源)。流量 SLI 作为辅助指标,用于容量规划而非 SLO 承诺。
2.5 SLI 设计决策树
当面对一个新服务时,可以按以下决策树逐步推导 SLI:
2.6 常见 SLI 设计误区
| 误区 | 表现 | 正确做法 |
|---|---|---|
| 指标过多 | 每个服务定义 10+ 个 SLI,团队无法聚焦 | 每个服务 ≤ 3 个核心 SLI,其余作为辅助指标 |
| 忽略隐式错误 | 仅监控 HTTP 5xx,遗漏业务逻辑错误 | 在应用层注入错误码,通过 OpenTelemetry 属性传递 |
| 使用均值 | 平均延迟 50ms,但 P99 高达 3s | 始终使用百分位数(P50/P95/P99) |
| 饱和度指标错误 | 监控 CPU 但瓶颈在数据库连接池 | 通过 profiling 和 tracing 找到真实瓶颈资源 |
| SLI 与 SLO 脱节 | SLI 定义很好,但 SLO 目标与业务容忍度不匹配 | SLI 好事件阈值直接映射到用户可接受的体验边界 |
快速自检:将你当前服务的 SLI 列表拿出来,对照上述误区逐条检查。如果发现 2 条以上命中,建议在下个迭代中重新设计 SLI 体系。
2.7 从 SLI 到 SLO 的映射
SLI 定义完成后,下一步是设定 SLO 目标。映射关系如下:
SLI 原始数据 → 好事件判定 → SLI 时间序列 → 窗口聚合 → SLO 达成率
示例:
SLI: 所有 HTTP GET 请求的 P99 延迟
好事件: P99 ≤ 200ms
测量窗口: 滚动 30 天
SLO: 99.9% 的 30 天窗口内,好事件占比 ≥ 99.5%
在 OpenTelemetry 管道中,SLI 数据通过以下路径流动:
- 采集层:OpenTelemetry Collector 接收 spans/metrics,提取延迟、错误码、资源利用率。
- 处理层:通过 OTTL(OpenTelemetry Transformation Language)计算百分位数、错误率、饱和度。
- 导出层:将处理后的 SLI 数据写入 Prometheus / Cortex / Thanos,用于 SLO 计算和告警。
关键结论:SLI 设计质量直接决定 SLO 的可信度。投入时间在 SLI 定义阶段,比后期调整 SLO 目标更高效。黄金信号提供了通用框架,但每个服务都需要根据自身架构和用户场景做定制化裁剪。