本篇文章为《基于 SLO 告警》系列文章第2篇,主要讲解基于 SLO 告警一般使用方法以及为什么要使用多窗口多燃烧率(MWMB)的方式。

对于基于 SLO 告警的一些基础概念,大家可以参考系列文章第1篇。

注意:

  • 文章大部分内容来自 Google 网站可靠性工作手册第5章,右下角可直接查看原文。
  • 示例中以 Prometheus rules 为例。

方法1:错误率≥SLO阈值

这种方法是大家最容易想到的,直接看最近一个较小时间窗口内(例如10分钟)目标错误率是否超过 SLO 阈值,如果超过即触发告警。

例如,30天的SLO为99.9%,过去10分钟内的错误率 ≥0.1% 时发出警报:

- alert: HighErrorRate
expr: job:slo_errors_per_request:ratio_rate10m{job="myjob"} >= 0.001

job:slo_errors_per_request:ratio_rate10m 指标可以使用 Prometheus 的 record rule 生成。

针对这种情况,假如服务 100% 中断大约 0.6s (10m*0.001)即可触发告警。

这种方法最大的问题是精度低,假如我们真的有一个服务,每隔10分钟就中断 0.6s,这意味着我们每天最多可以收到 144(24*6)个告警信息。即使我们什么都不做,依然能够满足 99.9% 的 SLO 目标。

方案2:增加观察窗口

方案 1 中我们使用了一个较小时间窗口(10分钟),这样可能会因为服务抖动导致频繁告警,为了降低告警频率,我们可以适当增加错误指标观察的时间窗口,比如变为36小时(占30天错误预算 5%)。

对应的告警规则为:

- alert: HighErrorRate
    expr: job:slo_errors_per_request:ratio_rate36h{job="myjob"} > 0.001

此时当业务 100% 中断大约2分钟10秒(36h*0.001)即可触发告警。

这种方法最大的问题是告警重置时间较长,假如业务 100% 中断2分钟10秒后,业务马上 100% 恢复,我们仍然要等到36小时后,才能收到告警恢复的通知。

方案3:告警持续性检测

这种方案主要使用一个较短的时间窗口,并观察其告警状态持续性,对应 Prometheus 中的告警规则就是使用 for ,比如:

- alert: HighErrorRate
    expr: job:slo_errors_per_request:ratio_rate1m{job="myjob"} > 0.001
    for: 1h

这种方法可以解决方案1中每隔 10m分钟中断0.6s 导致频繁告警的情况,又可以解决方案 2 中告警重置时间久的问题。

但这种方法也有一个致命问题,就是无法识别问题严重性,100% 错误率和 0.2% 错误率都需要持续1小时才能收到告警。

以1h 为例,假如 100% 中断的情况,当我们收到告警的时候,已经消耗了30天错误预算的 140%(60/43)。

方案4:基于单一燃烧率

前面3种方案都采用固定时间窗口和固定阈值的方式,为了改进方案,我们很自然想到基于错误预算燃烧耗率的方法,针对不同燃烧率我们可以配置不同告警级别,消耗越快,告警级别越高。

燃烧率与耗尽时间的关系如表格:

燃烧率 30 天 99.9% SLO的错误率 耗尽时间
1 0.1% 30天
2 0.2% 15天
10 1% 3天
1000 100% 43分钟

那么我们该使用怎样的燃烧率呢?

举个例子,在1小时内燃烧了30天错误预算的5%,这就需要触发告警了,此时可以得到燃烧率为 36 (30240.05/1)。

其告警规则为:

- alert: HighErrorRate
    expr: job:slo_errors_per_request:ratio_rate1h{job="myjob"} > 36 * 0.001

这种方法虽然解决前面提到的一些误报和恢复重置时间长的问题,但假如服务的燃烧率恰好只有35,意味着 20.5小时将消耗完所有的错误预算,而且您收不到任何告警。

方案5:基于多个燃烧率

方案4中只有一个固定的消耗率,针对固定 35 燃烧率的问题,我们可以使用多个燃烧率来避免,不同燃烧率可以对应不同告警级别。

比较建议的时间窗口和燃烧率,消耗的 SLO 百分比对照表如下:

消耗 SLO 预算 时间窗口 燃烧率 通知方式  
2% 1小时 14.4 呼叫  
5% 6小时 6 呼叫  
10%   3天 1 故障单

告警规则配置为:

expr: (
        job:slo_errors_per_request:ratio_rate1h{job="myjob"} > (14.4*0.001)
      or
        job:slo_errors_per_request:ratio_rate6h{job="myjob"} > (6*0.001)
      )
severity: page

expr: job:slo_errors_per_request:ratio_rate3d{job="myjob"} > 0.001
severity: ticket

这种方式能够解决方案4中的问题,但同一现象可能会触发多条告警,这意味着您需要更智能的告警抑制手段。

例如,五分钟内消耗了10%的预算,也意味着六小时内消耗了5%的预算,一小时内消耗了2%的预算,所以您可能会同时收到3条不同告警信息。

方案6:多窗口、多燃烧率

我们继续在方案5之上进行迭代,思路很简单,确保当前服务仍在不断消耗预算的时候才进行告警。

为此我们需要增加一个短时间观察窗口,一般短窗口的时间为长窗口的时间的1/12,只有两个时间窗口燃烧率都满足条件,才进行告警通知。

99.9% SLO警报配置的推荐参数表为:

消耗 SLO 预算 长期窗口 短期窗口 燃烧率 通知方式
2% 1小时 5分钟 14.4 呼叫
5% 6小时 30分钟 6 呼叫
10% 3天 6小时 1 故障单

所以最后告警规则配置大致为:

expr: (
        job:slo_errors_per_request:ratio_rate1h{job="myjob"} > (14.4*0.001)
      and
        job:slo_errors_per_request:ratio_rate5m{job="myjob"} > (14.4*0.001)
      )
    or
      (
        job:slo_errors_per_request:ratio_rate6h{job="myjob"} > (6*0.001)
      and
        job:slo_errors_per_request:ratio_rate30m{job="myjob"} > (6*0.001)
      )
severity: page

expr: (
        job:slo_errors_per_request:ratio_rate24h{job="myjob"} > (3*0.001)
      and
        job:slo_errors_per_request:ratio_rate2h{job="myjob"} > (3*0.001)
      )
    or
      (
        job:slo_errors_per_request:ratio_rate3d{job="myjob"} > 0.001
      and
        job:slo_errors_per_request:ratio_rate6h{job="myjob"} > 0.001
      )
severity: ticket

好了,到此我们想要的最终方法已经有了,即采用多窗口多燃烧率(MWMB)的方式。

总结

在基于 SLO 设计告警的时候,我们尽量采用 MWMB 的方法,它在告警及时性、告警重置恢复时间、误报、漏报都做了较好权衡。

但由于使用 MWMB 方法,对应的告警规则更为复杂,这给我们编写和维护规则配置文件带来了挑战。所以在实际工作中应该尽可能将其自动化,只需编写对应服务 SLO,即可按照 MWMB 方法,自动生成对应的告警规则(Prometheus alert/record rules)。

关于自动化部分我们会在后续实战文章中进行讲解,敬请期待。

  • 基于 SLO 告警(Part 1):基础概念
  • 基于 SLO 告警(Part 2):为什么使用 MWMB 方法
  • 基于 SLO 告警(Part 3):开源项目 sloth 使用
  • 基于 SLO 告警(Part 4):开源项目 pyrra 使用
  • 基于 SLO 告警(Part 5):SLO 多租户与服务化