3. SLI 口径定义:什么是 SLI 口径、常见的 SLI 类型
SLI(Service Level Indicator,服务等级指标)是衡量系统某一维度服务质量的具体量化指标。在可观测性体系中,SLI 口径定义了“我们测量什么”以及“如何测量”,是构建 SLO 和错误预算的基石。如果口径定义不清晰,后续的采集、聚合、告警都将失去意义。
3.1 什么是 SLI 口径
SLI 口径包含两个核心要素:测量对象和测量方法。测量对象指被监控的实体(如 HTTP 请求、数据库查询、消息队列长度),测量方法则定义了如何从原始数据中提取指标(如统计 P99 延迟、计算 5xx 错误占比)。
一个完整的 SLI 口径通常由以下部分组成:
| 组成部分 | 说明 | 示例 |
|---|---|---|
| 指标名称 | 唯一标识该 SLI 的命名 | http_request_duration_seconds |
| 数据来源 | 原始数据的采集位置 | API Gateway 访问日志、Agent 埋点 |
| 聚合方式 | 对原始数据进行统计计算的方法 | 平均值、百分位数(P50/P95/P99)、计数 |
| 时间窗口 | 指标计算的时间范围 | 1 分钟、5 分钟、滚动 30 天 |
| 过滤条件 | 排除或包含特定数据的规则 | 仅统计 status_code != 429 的请求 |
locals 或 variable,便于在多个模块间复用。例如:locals { sli_duration_p99 = { metric = "http_request_duration_seconds", quantile = 0.99, window = "5m" } }
3.2 四大黄金 SLI 类型
业界公认的四大黄金信号(Golden Signals)对应四种核心 SLI 类型:延迟、错误率、吞吐量和饱和度。这四类指标从不同维度覆盖了用户体验和系统健康度。
四大黄金 SLI 对比矩阵
| SLI 类型 | 测量对象 | 典型口径 | 常见阈值参考 |
|---|---|---|---|
| 延迟 | 请求响应时间 | P99 延迟 < 200ms | P50 < 100ms, P99 < 500ms |
| 错误率 | 失败请求占比 | HTTP 5xx 占比 < 0.1% | 错误率 < 1% 为警戒线 |
| 吞吐量 | 单位时间请求量 | RPS > 1000 | 根据业务峰值设定基线 |
| 饱和度 | 资源使用程度 | CPU 使用率 < 80% | 内存/磁盘/连接池 < 75% |
3.3 延迟(Latency)
延迟衡量系统处理请求所花费的时间,是用户体验最直接的体现。延迟 SLI 通常使用百分位数而非平均值,因为平均值容易掩盖长尾问题。
- P50(中位数):反映大多数用户的体验,适合作为日常监控基线。
- P95 / P99:反映最差情况下的体验,是 SLO 定义中最常用的口径。
- P999:用于对延迟极度敏感的场景(如金融交易、实时音视频)。
3.4 错误率(Error Rate)
错误率衡量失败请求占总请求的比例。错误定义需要根据业务语义明确区分:
| 错误类型 | 示例 | 是否计入 SLI |
|---|---|---|
| 显式错误 | HTTP 5xx、超时、连接拒绝 | 是 |
| 隐式错误 | 返回 200 但业务逻辑错误(如“订单创建失败”) | 建议计入 |
| 预期错误 | 429 限流、404 正常缺失 | 通常不计入 |
错误率口径定义示例:
# Prometheus 风格的 SLI 错误率查询
# 口径:过去 5 分钟内,HTTP 5xx 错误占总请求的比例
rate(http_requests_total{status_code=~"5.."}[5m])
/
rate(http_requests_total[5m])
3.5 吞吐量(Throughput)
吞吐量衡量系统在单位时间内处理的请求量或数据量。常见的吞吐量口径包括:
- RPS(Requests Per Second):每秒请求数,适用于 API 网关、Web 服务。
- TPS(Transactions Per Second):每秒事务数,适用于数据库、消息队列。
- 吞吐字节数:每秒处理的字节量,适用于文件传输、流媒体。
吞吐量 SLI 通常与延迟和错误率配合使用:当吞吐量突然下降时,往往意味着系统正在丢弃请求或发生故障。
3.6 饱和度(Saturation)
饱和度衡量系统资源被消耗的程度,通常表示系统还能承受多少额外负载。饱和度 SLI 是预测性指标,能在系统完全过载前发出预警。
| 资源类型 | 饱和度口径 | 说明 |
|---|---|---|
| CPU | CPU 使用率 / CPU 运行队列长度 | 运行队列 > 2×CPU 核数表示过载 |
| 内存 | 内存使用率 / OOM 事件计数 | 使用率 > 90% 需关注 |
| 磁盘 I/O | 磁盘队列深度 / I/O 等待时间 | 队列深度持续 > 磁盘并发数 |
| 网络 | 带宽使用率 / 丢包率 | 丢包率 > 0.1% 表示网络饱和 |
| 连接池 | 活跃连接数 / 最大连接数 | 活跃连接 > 80% 最大连接数 |
3.7 SLI 口径与 Terraform 模块的映射关系
在 Terraform 模块化部署中,每个 SLI 口径对应一组可重复使用的配置资源。下图展示了 SLI 口径定义如何映射到 Terraform 模块的输入变量和输出指标:
3.8 选择 SLI 口径的实用原则
- 用户视角优先:选择能直接反映用户体验的指标,而非内部实现细节。例如:用“页面加载时间”而非“数据库查询时间”。
- 可测量性:确保口径对应的原始数据能够稳定采集,避免依赖实验性或高成本的采集方式。
- 可操作性:每个 SLI 口径都应该能触发明确的运维动作。如果某个指标下降后团队不知道如何响应,则不应作为 SLI。
- 避免指标膨胀:每个服务建议定义 3~5 个核心 SLI,过多的 SLI 会导致监控疲劳和告警风暴。
Terraform 模块化建议:在 Terraform 中定义 SLI 口径时,建议使用 for_each 或 count 批量创建同类 SLI 资源。例如:
# 批量创建延迟 SLI 模块
variable "latency_slis" {
type = map(object({
quantile = number
threshold = number
window = string
}))
default = {
p50 = { quantile = 0.50, threshold = 100, window = "5m" }
p95 = { quantile = 0.95, threshold = 300, window = "5m" }
p99 = { quantile = 0.99, threshold = 500, window = "5m" }
}
}
module "latency_sli" {
for_each = var.latency_slis
source = "./modules/sli"
metric = "http_request_duration_seconds"
type = "latency"
quantile = each.value.quantile
threshold = each.value.threshold
window = each.value.window
}