简介

最近我在看 Prometheus 重启之后,报警自动解决并且稍后又重新触发的问题,所以就定位了一下原因,然后觉得可以从社区得到解决方案。没想到社区上已经有了解决方案,并且已经实现了,思路不谋而合,下面就翻译一下开发这个 feature 的人所写的一篇记录。


这恰好是我在 GSoC 期间解决的第一个问题。你可以在这里找到 PR#4061,它已经被合并到 Prometheus master 中,并且从 “v2.4.0 “开始就可以使用。

这篇文章假设你已经基本了解了什么是监控以及报警的关系。如果您是新手,那么 这篇文章 应该可以帮助您开始学习。

问题

简单来说,Prometheus 中的警报,一个警报规则由一个 条件for 持续时间和一个 黑盒 来处理警报。所以这里简单的技巧就是,如果 条件for 持续时间内是 true,我们就会触发一个警报(称为产生警报),并把它交给 黑匣子,让它按照自己想要的方式处理,可以是发送邮件,也可以是 Slack 消息等等。

前面说了报警的产生,假设你有一个 for 持续时间为 24小时 的警报,而 Prometheus 在该警报处于活动状态(conditiontrue)的 23小时 时崩溃,也就是说,在它即将触发前的 1 小时。现在,当 Prometheus 再次启动时,它将不得不再次等待 24小时 后才会触发!你可以在这里找到 GitHub issue #422

修复方式

用时间序列来存储状态!在 Prometheus 中的代码就是这么处理的。

  1. 在每次评估告警规则的过程中,我们将历史的告警的 ActiveAt(什么时候 condition 第一次变成了 true)记录在一个名称为 ALERTS_FOR_STATE 的时间序列中,其中包括该告警的所有标签。这和其他时间序列一样,但只存储在本地;
  2. 当 Prometheus 被重新启动时,会有一个工作运行,用于恢复第二次评估后的警报状态。我们等到第二次评估时,这样我们就有足够的采集数据来了解当前的活跃报警;
  3. 对于每一个当前处于活跃状态的报警,作业寻找其对应的 ALERTS_FOR_STATE 时间序列。时间戳和 series 的最后一个样本的值给我们提供了 Prometheus 什么时候宕机的信息,以及报警最后活跃的时间;
  4. 因此,如果 for 持续时间是 D,报警在 X 开始激活,而Prometheus在 Y 崩溃,那么警报必须等待更多 D-(Y-X) 持续时间(为什么?想想看!)。所以对警报的变量进行调整,让它等待更多的 D-(Y-X) 时间再触发,而不是D

需要注意的事项

注意:只有当 for 持续时间本身是 ≥rules.alert.for-grace-period 时,我们才会遵循这个逻辑。

疑难杂症

由于 ALERTS_FOR_STATE series 存储在本地存储中,如果在 Prometheus 宕机时恰好丢失了本地的 TSDB 数据,那么就会永久丢失报警的状态。

Ref

本文基本上都是翻译自:Google Summer of Code 2018 with Prometheus