Prometheus 告警恢复时,怎么获取恢复时的值?
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 不会这么干的,核心是:
- 从职能上,Alertmanager 去查询 Prometheus,就反向依赖了,Alertmanager 是告警的分发中心,不止是接收 Prometheus 推送过来的事件,还会接收其他告警源推送过来的事件,如果 Alertmanager 要去查询 Prometheus,那就耦合太过严重。
- Prometheus 的告警规则中可以附加标签,和监控指标的标签一起,作为事件的标签集发给 Alertmanager,Alertmanager 需要根据这些标签去查询 Prometheus,拿到原始数据,这在某些场景下是不可行的。一个是要把标签中的附加标签剔除,只留数据标签,Alertmanager 没有办法做到;其次,有些 promql 查询结果压根就没有标签,根本没法查;再次,Alertmanager 需要解析 promql,把阈值的部分拿掉,而有些 promql 压根就不是数字阈值。
如果你想通过修改 Alertmanager 达成所愿,放弃吧。
有没有办法解决?
有。通常的解决办法有两种:
- 告警规则里,顺便配置恢复时的 promql
- 把阈值从 promql 中拿掉,promql 只用于查询原始数据,然后在上层做阈值判定,不管监控指标当前是否健康,都会查到原始数据
下面我以一些监控产品为例,具体来说明。
告警规则里配置恢复时的 promql
使用这个方法的产品,以夜莺(Nightingale)监控为例,来讲解具体做法。核心是配置两个地方,一个是在告警规则里配置恢复时的 promql,另一个是在告警模板里配置恢复时的值的渲染。
比如我有一个告警规则用来侦测 HTTP 地址探测失败:
需要在告警规则最下面的自定义字段里,增加 recovery_promql 的配置,如下:
要理解这个工作逻辑,我们先来看看 http_response_result_code 这个指标的数据长什么样子:
从上图可以看出,这个指标包含两个 series,其中 agent_hostname 和 method 字段相同,target 字段可以区分开这俩 series。告警规则 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 就展示,展示的时候把 recovery_value 保留 4 位小数。这个 .AnnotationsJSON 是夜莺告警规则中的自定义字段部分,如果告警事件中有恢复时的值,就会在这个字段中体现。
最终效果如下:
把阈值从 promql 中拿掉,promql 只用于查询原始数据
使用这个做法的产品,以 FlashDuty 举例,FlashDuty 不但支持类似夜莺这样的配置 recovery_promql 的方式,还支持 promql 中不带阈值的方式。我们重点讲解 promql 中不带阈值的方式。
以 Memcached 的某个告警规则举例,查询条件里不写阈值,判定规则里写阈值,如下图所示:
这种方式需要先查到当前值,再拿着当前值去做判定,所以不管是告警时还是恢复时,都可以拿到当前值。这种方式非常直观,大部分场景都适用。对于一个查询条件过滤到很多时序的场景,这种方式会查到特别多的数据,对告警引擎也是个压力。需要斟酌。
如果你也想让自己的监控系统支持在恢复时拿到恢复时的值,可以参考上述两种方式。
Prometheus 告警恢复时,怎么获取恢复时的值?的更多相关文章
- input date 赋值的坑及改变时如何获取 input date的值
- 【转】Java Web 项目获取运行时路径 classpath
Java Web 项目获取运行时路径 classpath 假设资源文件放在maven工程的 src/main/resources 资源文件夹下,源码文件放在 src/main/java/下, 那么ja ...
- servlet获取参数时,request.getParameter("id")参数获取失败
servlet获取参数时,request.getParameter("id")参数获取失败,这里的参数是“index”里面href中的参数 要注意,取不到值,是不是要取的参数有没有 ...
- 【Android端 APP 启动时长获取】启动时长获取方案及具体实施
一.什么是启动时长? 1.启动时长一般包括三种场景,分别是:新装包的首次启动时长,冷启动时长.热启动时长 冷启动 和 热启动 : (1)冷启动:当启动应用时,后台没有该程序的进程,此时启动的话系统会分 ...
- Javascript 笔记与总结(2-9)获取运行时的 style 对象
获取内存中(正在渲染)的 style 的值(非内联 style,obj.style 只能获得内联 style 的值),可以用 obj.currentStyle(低版本 IE 和 Opera 支持)和 ...
- js中使用控件名和数组下标方式获取控件的值时失败
在做界面展示时涉及到表单行项目的增加和删除时,我们一帮都使用js的脚本实现表单行的增加和删除,那么在进行表单的提交的时我们会再页面上进行提交数据的初步校验,进行数据的初步校验时,就要动态获取控件的值. ...
- 使用mini-textbox控件时 不能获取value值
当使用class=“mini-textbox”文本框时 使用document.getElementById('id').value 获得的文本框输入值是‘undefined’而使用正常的input 不 ...
- java 代码获取视频时长
package test; import it.sauronsoftware.jave.Encoder; import it.sauronsoftware.jave.MultimediaInfo; i ...
- vue / js使用video获取视频时长
项目中遇到上传视频功能,需要有预览和获取视频时长功能,因之前使用upload(有需要的话可以参考下我之前的文章),这里就不赘述,直接用来上传视频,不过在上传之前和上传成功后的钩子里,获取不到时长: 没 ...
- VUE.JS 窗口发生变化时,获取当前窗口的高度。
VUE.JS # 窗口发生变化时,获取当前窗口的高度. mounted () { const that = this; window.onresize = () => { return (() ...
随机推荐
- ubuntu pyinstaller 的安装以及使用
使用pyinstaller将Python文件打包成linux可执行文件. 安装pip3: sudo apt-get install python3-pip 更换pip3下载源: 1 sudo su 2 ...
- JDK9之后 Eureka依赖
<!--Eureka添加依赖开始--> <dependency> <groupId>javax.xml.bind</groupId> <artif ...
- 记一次 CDN 流量被盗刷经历
先说损失,被刷了 70 多RMB,还好止损相对即时了,亏得不算多,PCDN 真可恶啊. 600多G流量,100多万次请求. 怎么发现的 先是看到鱼皮大佬发了一篇推文突发,众多网站流量被盗刷!我特么也中 ...
- odoo 通过Javascript显示或隐藏form自带按钮
实践环境 Odoo 14.0-20221212 (Community Edition) 需求描述 如下,根据条件对form视图自带按钮的显示.隐藏进行控制 代码实现 隐藏.显示编辑和创建按钮为例 od ...
- Fiddler使用界面介绍-左侧会话面板
左侧会话面板,是Fiddler抓取的请求数据展示
- SptingBoot同时接收文件和对象数据(接收表单数据)
emmm...虽然很简单,而且网上全是教程,但是自己做个笔记映像才会更深刻,还请各位前辈多多指教: @RequestMapping(value = "/eventPush", me ...
- 【Java】Reflection 反射机制 01概述
Reflection 反射机制 反射允许程序在执行期间借助ReflectionAPI获取任何类的内部信息,直接操作任意对象的内部属性和方法 加载完类之后,堆内存的方法区产生了一个Class 类类型的对 ...
- 【H5】07 网页调试
摘自: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML HTML 优雅明 ...
- 如何使用二阶优化算法实现对神经网络的优化 —— 分布式计算的近似二阶优化算法实现对神经网络的优化 —— 《Distributed Hessian-Free Optimization for Deep Neural Network》
论文: <Distributed Hessian-Free Optimization for Deep Neural Network> 地址: https://arxiv.org/abs/ ...
- Jax框架:通过显存分析判断操作是否进行jit编译
相关: https://jax.readthedocs.io/en/latest/device_memory_profiling.html 代码: import jax import jax.nump ...