本篇文章为《基于 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 (30*24*0.05/1)。
其告警规则为:
```
- alert: HighErrorRate
expr: job:slo_errors_per_request:ratio_rate1h{job="myjob"} > 36 * 0
```
这种方法虽然解决前面提到的一些误报和恢复重置时间长的问题,但假如服务的燃烧率恰好只有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 多租户与服务化
----
更多文章,请关注我们公众号 [【Grafana 爱好者】](https://mp.weixin.qq.com/s/tbyX7-3qGcHUDj5Igv5clQ)。
有疑问加站长微信联系(非本文作者))