1. SLI 基础概念:什么是 SLI,在 GitLab CI 流水线中的定义与重要性
1.1 SLI 的定义与核心公式
SLI(Service Level Indicator,服务等级指标) 是对服务某个特定维度进行量化的度量值。在 SRE 实践中,SLI 是回答“服务到底有多好”的原始数据,通常表示为一段时间内的好事件计数 / 总事件计数。
| 维度 | 典型 SLI 示例 | 计算公式 |
|---|---|---|
| 可用性 | 请求成功率 | 成功请求数 / 总请求数 × 100% |
| 延迟 | P95 响应时间 ≤ 200ms | 满足阈值请求数 / 总请求数 × 100% |
| 吞吐量 | 每分钟处理作业数 | 已完成作业数 / 时间窗口(分钟) |
| 错误率 | HTTP 5xx 占比 | 错误响应数 / 总响应数 × 100% |
关键认知: SLI 是原始测量值,不是目标值。目标值由 SLO(Service Level Objective)定义。例如:“流水线成功率 SLI = 98.5%”是测量结果,“SLO = 99%”是承诺目标。
1.2 SLI 在 GitLab CI 流水线中的定义
在 GitLab CI 流水线上下文中,SLI 将传统 SRE 概念映射到 CI/CD 的作业执行、阶段流转、流水线完成三个核心层面。每个 SLI 都对应一个可观测的计数事件。
- 流水线级 SLI: 流水线整体成功率、流水线总耗时、流水线阻塞率。
- 阶段级 SLI: 构建阶段成功率、测试阶段通过率、部署阶段回滚率。
- 作业级 SLI: 单个 job 执行成功率、job 排队等待时间、job 超时率。
# GitLab CI SLI 口径示例(Prometheus 指标格式)
# 流水线成功率 SLI
ci_pipeline_success_total{status="success"} / ci_pipeline_success_total{status=~"success|failed"} * 100
# 作业排队延迟 SLI(P95)
histogram_quantile(0.95, sum(rate(ci_job_duration_seconds_bucket{type="queue"}[5m])) by (le))
# 部署回滚率 SLI
ci_deployment_rollback_total / ci_deployment_total * 100
实践要点: 定义 GitLab CI SLI 时,必须明确好事件与总事件的边界。例如:手动取消的流水线是否计入分母?基础设施故障导致的失败是否排除?这些口径差异会直接影响 SLI 数值和告警灵敏度。
1.3 SLI 在 GitLab CI 中的重要性
没有 SLI,流水线健康度就是“黑盒”。SLI 为以下四个关键场景提供数据基础:
- 故障排查: 通过 SLI 趋势图快速定位是成功率下降还是延迟飙升,缩小排查范围。
- 告警降噪: 基于 SLI 的 SLO 燃烧率告警,避免“每失败一次就告警”的噪声风暴。
- 容量规划: 作业排队 SLI 反映 Runner 资源瓶颈,指导扩缩容决策。
- 发布质量门禁: 将 SLI 嵌入流水线,失败率超过阈值时自动阻断后续阶段。
1.4 SLI 与 SLO、错误预算的关系
在 GitLab CI 场景中,SLI、SLO、错误预算三者构成可观测性闭环:
| 概念 | 定义 | GitLab CI 示例 |
|---|---|---|
| SLI | 实际测量值 | 过去 7 天流水线成功率为 97.2% |
| SLO | 目标阈值 | 流水线成功率 ≥ 99% |
| 错误预算 | 允许失败的上限 | 7 天内允许失败 1% 的流水线(约 10 次) |
常见误区: 不要将 SLI 直接当作告警阈值。例如:流水线成功率 SLI 降到 95% 才告警,此时错误预算可能已经烧光。正确的做法是使用燃烧率告警,在错误预算消耗速度过快时提前介入。
1.5 定义 GitLab CI SLI 的最佳实践
- 从用户旅程出发: 开发者最关心的是“我的 MR 流水线是否通过”,因此 MR 流水线成功率是首要 SLI。
- 区分失败类型: 基础设施失败(Runner 离线)与应用代码失败(测试未通过)应拆分为独立 SLI,避免混为一谈。
- 设置时间窗口: 使用滚动窗口(如 7 天、30 天)计算 SLI,避免单次失败导致剧烈波动。
- 标签化维度: 利用 GitLab CI 标签(如分支、作业名、阶段名)对 SLI 进行多维切片,提升排查效率。
# 多维 SLI 查询示例(PromQL)
# 按分支维度查看成功率
sum by (ref) (rate(ci_pipeline_success_total{status="success"}[7d]))
/
sum by (ref) (rate(ci_pipeline_success_total[7d]))
* 100