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 为以下四个关键场景提供数据基础:

  1. 故障排查: 通过 SLI 趋势图快速定位是成功率下降还是延迟飙升,缩小排查范围。
  2. 告警降噪: 基于 SLI 的 SLO 燃烧率告警,避免“每失败一次就告警”的噪声风暴。
  3. 容量规划: 作业排队 SLI 反映 Runner 资源瓶颈,指导扩缩容决策。
  4. 发布质量门禁: 将 SLI 嵌入流水线,失败率超过阈值时自动阻断后续阶段。
SLI 在 GitLab CI 流水线中的核心作用 GitLab CI SLI 故障排查 告警降噪 容量规划 发布质量门禁 💡 核心价值: 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