2. SLI 定义与分类:延迟、错误率、吞吐量、饱和度
SLI(Service Level Indicator,服务等级指标)是衡量系统某一维度服务质量的具体量化指标。在 SRE 实践中,SLI 通常被归纳为四大黄金信号:延迟、错误率、吞吐量 和 饱和度。准确理解每个 SLI 的定义及其采集方式,是构建可靠 SLO 作业模板的基础。
2.1 四大黄金信号概览
| SLI 类别 | 核心定义 | 典型采集方式 | 常见指标名称 |
|---|---|---|---|
| 延迟 (Latency) | 请求从发出到收到完整响应所消耗的时间 | 服务端埋点、APM 探针、负载均衡日志 | p50, p95, p99 延迟 |
| 错误率 (Error Rate) | 失败请求数占总请求数的比例 | HTTP 状态码统计、应用异常计数、健康检查 | 5xx 占比、超时率、异常率 |
| 吞吐量 (Throughput) | 系统在单位时间内成功处理的请求量 | 请求计数器、消息队列消费速率、数据库 QPS | RPS, QPS, TPS |
| 饱和度 (Saturation) | 系统资源被使用的程度,通常反映排队或过载 | CPU 使用率、内存占用、磁盘 I/O 队列深度 | CPU 饱和度、内存利用率、连接池占用率 |
实践要点: 并非所有服务都需要同时监控四个黄金信号。对于无状态 API 服务,延迟和错误率是首要 SLI;对于数据库或消息队列,饱和度和吞吐量往往更关键。选择 SLI 时应遵循“少而精”原则,每个服务通常只定义 2~3 个核心 SLI。
2.2 延迟 SLI:定义与采集
定义: 延迟 SLI 衡量系统响应速度,通常以百分位数(Percentile)表示。例如:“99% 的请求在 200ms 内完成”。延迟 SLI 能直接反映用户体验,是大多数在线服务的核心指标。
采集方式:
- 服务端埋点: 在应用代码中记录每个请求的开始时间和结束时间,计算差值后上报到时序数据库(如 Prometheus、InfluxDB)。
- APM 探针: 使用 SkyWalking、Jaeger 等分布式追踪工具,自动采集跨服务调用的链路延迟。
- 负载均衡日志: 从 Nginx、HAProxy 等反向代理的访问日志中解析 upstream_response_time 字段。
# 示例:Prometheus Histogram 采集延迟
# 在应用代码中定义 Histogram 指标
request_duration_seconds = Histogram(
'http_request_duration_seconds',
'HTTP request latency in seconds',
buckets=[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]
)
# 记录每个请求的耗时
request_duration_seconds.observe(elapsed_time)
常见误区: 仅监控平均延迟(Avg Latency)会掩盖长尾问题。例如:平均延迟 50ms 的服务,可能 p99 延迟高达 2s。SLO 作业模板中应始终使用高百分位延迟(p95 或 p99)作为 SLI 目标。
2.3 错误率 SLI:定义与采集
定义: 错误率 SLI 衡量请求失败的占比。错误不仅包括 HTTP 5xx 状态码,还应涵盖业务逻辑错误(如“库存不足”、“鉴权失败”)和超时错误。公式为:错误率 = 错误请求数 / 总请求数 × 100%。
采集方式:
- HTTP 状态码统计: 从网关或应用日志中聚合 5xx 和 4xx 状态码数量,除以总请求数。
- 应用异常计数器: 在代码中捕获业务异常并上报到监控系统(如 Prometheus Counter)。
- 健康检查探针: 定期对关键接口发起探测请求,统计失败次数。
# 示例:Prometheus Counter 采集错误率
# 定义两个 Counter:总请求数和错误请求数
total_requests = Counter('http_requests_total', 'Total HTTP requests')
error_requests = Counter('http_requests_errors', 'HTTP request errors')
# 在请求处理逻辑中
total_requests.inc()
if response.status_code >= 500:
error_requests.inc()
# 查询错误率(PromQL)
rate(http_requests_errors[5m]) / rate(http_requests_total[5m]) * 100
SLI 设计建议: 错误率 SLI 应区分“显式错误”(如 5xx)和“隐式错误”(如返回 200 但业务失败)。对于关键业务,建议将隐式错误也纳入 SLI 计算,避免“假成功”掩盖真实故障。
2.4 吞吐量 SLI:定义与采集
定义: 吞吐量 SLI 衡量系统处理请求的能力,通常以每秒请求数(RPS)、每秒查询数(QPS)或每秒事务数(TPS)表示。吞吐量下降往往是系统出现瓶颈的前兆。
采集方式:
- 请求计数器: 在服务入口处统计每秒通过的请求数量,使用 Prometheus Counter 配合 rate() 函数计算。
- 消息队列消费速率: 从 Kafka、RabbitMQ 等中间件获取消费组每秒处理的消息数。
- 数据库 QPS: 从数据库监控工具(如 MySQL 的 SHOW GLOBAL STATUS)采集每秒查询次数。
# 示例:PromQL 查询吞吐量
# 计算过去 5 分钟的平均 RPS
rate(http_requests_total[5m])
# 按不同路由分组查看吞吐量
sum by (route) (rate(http_requests_total[5m]))
关联性: 吞吐量 SLI 通常与延迟 SLI 呈负相关。当吞吐量接近系统上限时,延迟会急剧上升(即“拐点”)。SLO 作业模板中可将吞吐量作为延迟的辅助预警指标。
2.5 饱和度 SLI:定义与采集
定义: 饱和度 SLI 衡量系统资源被消耗的程度,反映系统是否接近容量上限。饱和度通常与排队理论相关,当资源利用率超过某个阈值(如 CPU 80%)时,系统性能会非线性下降。
采集方式:
- CPU 饱和度: 使用 node_exporter 采集 CPU 使用率,或通过 /proc/stat 计算 CPU 空闲时间。
- 内存饱和度: 监控内存使用率、Swap 使用量、OOM Killer 事件。
- 连接池饱和度: 采集数据库连接池、线程池的活跃连接数与最大连接数之比。
- 磁盘 I/O 饱和度: 监控磁盘 I/O 队列深度(avgqu-sz)和等待时间(await)。
# 示例:PromQL 查询 CPU 饱和度
# CPU 使用率(排除空闲时间)
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 连接池饱和度(以 MySQL 为例)
mysql_global_status_threads_connected / mysql_global_variables_max_connections
关键原则: 饱和度 SLI 应优先关注“排队指标”而非简单的使用率。例如:磁盘使用率 90% 可能不影响性能,但磁盘 I/O 队列深度持续大于 2 则表明已饱和。SLO 作业模板中建议将饱和度阈值设置为 70%~80%,预留缓冲空间。
2.6 SLI 分类与采集架构图
下图展示了四大黄金信号在典型微服务架构中的采集位置与数据流向:
2.7 SLI 选择决策矩阵
在实际作业模板中,不同服务类型应优先关注不同的 SLI 组合。下表提供了推荐选择:
| 服务类型 | 首要 SLI | 次要 SLI | 可选 SLI |
|---|---|---|---|
| Web API / 网关 | 延迟 (p99) | 错误率 | 吞吐量 |
| 数据库 / 缓存 | 饱和度 | 延迟 (p95) | 吞吐量 |
| 消息队列 | 吞吐量 | 延迟 (消费延迟) | 饱和度 |
| 批处理 / 离线任务 | 吞吐量 | 错误率 | 饱和度 |
| CDN / 静态资源 | 延迟 (首字节时间) | 错误率 | 吞吐量 |
多维聚合思路: 单个 SLI 无法全面反映服务质量。例如:延迟正常但错误率飙升,说明系统可能返回了快速失败响应。在 SLO 作业模板中,建议将延迟和错误率组合成“可用性”维度,将吞吐量和饱和度组合成“容量”维度,实现更精准的自动调整。