prometheus + alertmanager的搭配如何判定告警恢复

场景

一般我们监控由prometheus发送告警给alertmanager,然后由alertmanager来推送告警,那么此时,告警的恢复除了prometheus来触发外,其实也可以由alertmanager来发送的

告警恢复的触发过程

prometheus触发告警恢复:

  • 对于已经恢复的告警指标,如果之前是pending或者之前的ResolvedAt非空,且
    在resolvedRetention(15m)之前的,则删除此告警;
    否则更新告警的状态为恢复,且恢复的时间为当前时间

  • 对告警进行判断是否需要发送
    恢复时间是大于上次发送告警的时间,证明恢复是在告警后发生的,那么已经恢复了,需发送恢复

  • 设置告警的ValidUntil,如果这条告警过了ValidUntil的话,还没收到新firing,则代表恢复:

    ValidUntil = ts + max([check_interval], [resend_delay]) * 4

  • 发送前设置告警EndAt

    • 如果告警的ResolvedAt不空,则EndsAt = ResolvedAt,否则等于ValidUntil;
      也就是说如果告警的ResolvedAt不空,证明是采集到了恢复的情况,EndAt代表实际恢复实际
    • 如果告警的ResolvedAt为空,则还没有恢复,设置其为一个ValidUntil,就是告警的有效时间,就是说如果持续了ValidUntil之后,没有收到新的firing,则当作恢复来处理
  • 发送告警

alertmanager触发告警恢复:

注意:Alertmanager 里必须有 Inactive 消息所对应的告警,否则是会被忽略的。换句话说如果一个告警在 Alertmanager 里已经解除了,再发同样的 Inactive 消息,Alertmanager 是不会发给 webhook 的。

Prometheus 需要 持续 地将 Firing 告警发送给 Alertmanager,遇到以下一种情况,Alertmanager 会认为告警已经解决,发送一个 resolved:

  • Prometheus 发送了 Inactive 的消息给 Alertmanager,即 endsAt=当前时间

  • Prometheus 在上一次消息的 endsAt 之前,一直没有发送任何消息给 Alertmanager

    解释:prometheus发送给alertmanager的告警触发消息里是带有一个endAt时间,用来告知如果超过这个时间没有再收到新的告警就认为告警已经恢复,如果prometheus没有带endAt,那么alertmanager会设置endAt为now + resolve_timeout,作为默认恢复时间

    prometheus会给告警加上一个默认endAt:ts + max([check_interval], [resend_delay]) * 4

    • resendDelay,是程序启动参数 --rules.alert.resend-delay 规定的,默认 1m
    • interval,是我们配置的采集间隔

原理:当AlertManager收到告警实例之后,会分以下几类情况对这两个字段进行处理:

  • 1、两者都存在:不做处理
  • 2、两者都未指定:startsAt指定为当前时间,endsAt为当前时间加上告警持续时间,默认为5分钟
  • 3、只指定startsAt:endsAt指定为当前时间加上默认的告警持续时间
  • 4、只指定endsAt:将startsAt设置为endsAt

即:如果 endsAt 没有提供,则自动等于 startsAt + resolve_timeout(默认 5m),如果有指定,则以指定的为准

alertmanager resolve_timeout

alertmanager config中可以看到默认的resolve_timeout是5m,且是一个可以配置的值。
该参数定义了当Alertmanager持续多长时间未接收到告警后标记告警状态为resolved(已解决)。
该参数的定义会影响到告警恢复通知的接收时间。

global:
  [ resolve_timeout: <duration> | default = 5m ]
  [ smtp_from: <tmpl_string> ] 
  [ smtp_smarthost: <string> ] 
  [ smtp_hello: <string> | default = "localhost" ]
  [ smtp_auth_username: <string> ]
  [ smtp_auth_password: <secret> ]
  [ smtp_auth_identity: <string> ]
  [ smtp_auth_secret: <secret> ]
  [ smtp_require_tls: <bool> | default = true ]
  [ slack_api_url: <secret> ]
  [ victorops_api_key: <secret> ]
  [ victorops_api_url: <string> | default = "https://alert.victorops.com/integrations/generic/20131114/alert/" ]
  [ pagerduty_url: <string> | default = "https://events.pagerduty.com/v2/enqueue" ]
  [ opsgenie_api_key: <secret> ]
  [ opsgenie_api_url: <string> | default = "https://api.opsgenie.com/" ]
  [ hipchat_api_url: <string> | default = "https://api.hipchat.com/" ]
  [ hipchat_auth_token: <secret> ]
  [ wechat_api_url: <string> | default = "https://qyapi.weixin.qq.com/cgi-bin/" ]
  [ wechat_api_secret: <secret> ]
  [ wechat_api_corp_id: <string> ]
  [ http_config: <http_config> ]

templates:
  [ - <filepath> ... ]

route: <route>

receivers:
  - <receiver> ...

inhibit_rules:
  [ - <inhibit_rule> ... ]

解释:为什么一条持续触发的告警不会触发恢复,而采集不到数据时会触发恢复

如果告警一直 Firing,那么 Prometheus 会在 resend_delay 的间隔重复发送,而 startsAt 保持不变, endsAt 跟着 ValidUntil 变。这也就是为啥一直firing的规则不会被认为恢复,而不发firting则会认为恢复。因为一直firing的告警消息中, endsAt 跟着 ValidUntil 变,一直在后延。而如果没收到,就会导致alertmanger那边在过了告警的endAt时间后,没收到恢复或者新firing,则认为恢复

总结告警恢复的过程

  • prometheus采集到了告警恢复的情况,推送给alertmanager,alertmanager发出告警

  • prometheus发送了告警消息,且没有发生恢复告警,也没有持续发送触发告警,则alertmanger对一条活跃告警如果过了这条告警的endAt时间后会发出告警恢复的消息

  • 当告警没有再此触发时,多久后发送恢复的时间由什么因素决定:告警的endAt来决定

    • 告警的endAt默认情况下prometheus会设置为以下值来决定:
      • ts + max([check_interval], [resend_delay]) * 4
        resendDelay,是程序启动参数 --rules.alert.resend-delay 规定的,默认 1m
        interval,是我们配置的采集间隔
    • 如果收到的告警里没有设置endAt,那么alertmanager设置endAt为以下值来决定:
      • now + resolve_timeout
  • 即:对活跃告警的默认恢复时间决定为:如果发送方(prometheus等)指定了endAt,则以发送方为准,否则alertmanger统一设置为now + resolve_timeout,即一条告警等待了resolve_timeout还没收到新的告警内容,则视为恢复

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐