当前位置:首页 > 技术 > 正文内容

Prometheus 告警恢复时如何获取实际值

访客 技术 2026年7月2日 1

在 Prometheus 监控系统中,告警事件中的 $value 展示的是告警触发时的数值。然而,当告警恢复时,Resolved 事件中的 $value 仍然显示的是告警触发时的值,而非恢复时的实际数值。这是为什么呢?是否有解决方法?

原理解析

告警规则配置在 prometheus.yaml 文件中,由 Prometheus 负责执行规则判断。Prometheus 的判断逻辑相对简单:周期性地执行 PromQL 查询,如果查询结果连续多次满足 for 指定的持续时间,则触发告警事件;如果查询无结果,则认为指标处于正常健康状态。

例如:

cpu_usage_idle < 5

在上述告警规则中,PromQL 包含阈值条件(< 5)。当查询到数据时,表示当前值小于 5;当查询无结果时,表示当前值大于等于 5,即处于健康状态。值得注意的是,当数据正常时,时序数据库不返回数据,这意味着监控系统无法获取正常状态下的值,因此在恢复时无法展示最新的数值。

实际上,恢复事件是由 Alertmanager 根据 resolve_timeout 生成的,而非 Prometheus。Alertmanager 生成恢复事件时,会保留上次告警的标签和注解,但数值仍然是上次告警时的值,Alertmanager 不会重新查询 Prometheus 获取最新数值。

Alertmanager 能否获取恢复时的值?

坦率地说,这非常困难。Alertmanager 需要根据上次告警的标签和注解查询 Prometheus 获取历史值,但 Alertmanager 不会这样做,主要原因包括:

  1. 从职能角度看,如果 Alertmanager 查询 Prometheus,会造成反向依赖,因为 Alertmanager 是告警分发中心,不仅接收 Prometheus 推送的事件,还可能接收其他告警源的事件,过度耦合不利于系统架构。

  2. Prometheus 的告警规则可以附加标签,这些标签与监控指标的标签一起作为事件的标签集发送给 Alertmanager。Alertmanager 需要根据这些标签查询 Prometheus 获取原始数据,这在某些场景下不可行:

  • 需要从标签中剔除附加标签,只保留数据标签,但 Alertmanager 无法完成此操作
  • 某些 PromQL 查询结果没有标签,无法查询
  • Alertmanager 需要解析 PromQL 并移除阈值部分,但某些 PromQL 并非基于数字阈值

试图通过修改 Alertmanager 来解决这个问题是不现实的。

解决方案

有两种常用解决方案:

  1. 在告警规则中配置恢复时的 PromQL
  2. 将阈值从 PromQL 中移除,仅使用 PromQL 查询原始数据,然后在高层进行阈值判定

方案一:在告警规则中配置恢复时的 PromQL

以 Nightingale 监控系统为例,说明具体实现方法。核心是在两个地方进行配置:告警规则中配置恢复时的 PromQL,以及在告警模板中配置恢复值的渲染。

例如,有一个用于检测 HTTP 地址探测失败的告警规则:

需要在告警规则的自定义字段部分添加 recovery_promql 配置:

recovery_promql: http_response_result_code{target="{{.target}}"}

理解这一工作逻辑,我们先查看 http_response_result_code 指标的数据结构:

该指标包含多个时间序列,其中 agent_hostname 和 method 字段相同,target 字段用于区分不同时间序列。告警规则 http_response_result_code != 0 触发时,告警事件中会包含 target 标签。因此,当告警恢复时,我们可以使用告警时的 target 标签查询,准确获取恢复时的值。在 recovery_promql 配置中引用了 target 标签,该变量取自告警事件中的 target 标签值。

在告警模板中,添加恢复值的渲染逻辑。以钉钉模板为例:

{{if .IsRecovered}}<font color="#008800">💚{{.RuleName}}</font>{{else}}<font color="#FF0000">💔{{.RuleName}}</font>{{end}}

---
{{$time_duration := sub now.Unix .FirstTriggerTime }}{{if .IsRecovered}}{{$time_duration = sub .LastEvalTime .FirstTriggerTime }}{{end}}
- **告警级别**: {{.Severity}}级
{{- if .RuleNote}}
- **规则备注**: {{.RuleNote}}
{{- end}}
{{- if not .IsRecovered}}
- **触发时值**: {{.TriggerValue}}
- **触发时间**: {{timeformat .TriggerTime}}
- **持续时长**: {{humanizeDurationInterface $time_duration}}
{{- else}}
{{- if .AnnotationsJSON.recovery_value}}
- **恢复时值**: {{formatDecimal .AnnotationsJSON.recovery_value 4}}
{{- end}}
- **恢复时间**: {{timeformat .LastEvalTime}}
- **持续时长**: {{humanizeDurationInterface $time_duration}}
{{- end}}
- **告警标签**:
{{- range $key, $val := .TagsMap}}
{{- if ne $key "rulename" }}
  - `{{$key}}`: `{{$val}}`
{{- end}}
{{- end}}

关键逻辑是判断 .AnnotationsJSON.recovery_value

{{- if .AnnotationsJSON.recovery_value}}
- **恢复时值**: {{formatDecimal .AnnotationsJSON.recovery_value 4}}
{{- end}}

如果 .AnnotationsJSON 中包含 recovery_value,则显示该值,保留4位小数。.AnnotationsJSON 是夜莺告警规则中的自定义字段部分,如果告警事件包含恢复时的值,会在此字段中体现。

方案二:将阈值从 PromQL 中移除

以 FlashDuty 为例,它支持在 PromQL 中不包含阈值的方式。我们重点讲解这种方法。

以 Memcached 的告警规则为例,查询条件中不写阈值,在判定规则中写阈值:

这种方式需要先查询当前值,然后进行阈值判定,因此在告警触发和恢复时都能获取当前值。这种方式非常直观,适用于大多数场景。但对于查询条件过滤出大量时间序列的场景,这种方式会查询大量数据,对告警引擎造成压力,需要谨慎使用。

如果您希望自己的监控系统能够在告警恢复时获取实际值,可以参考上述两种方法实现。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。