什么是RecodingRules?
将计算频繁需要或计算成本高昂的表达式的结果保存为一组新的时间序列。然后,查询预先计算的结果通常会比每次需要时都执行原始表达式快得多。这对于仪表盘特别有用,因为仪表盘每次刷新时都需要反复查询相同的表达式。
Recording是一种特殊的报警规则,将计算/书写复杂的PromeQL预先定义好,然后输出为看起来更直观更简单的series和value,在其他报警中直接使用这个新的series作为报警条件即可,如下图:

报警抑制规则复杂性问题
在实际场景中,比如组内的多个SRE在配置报警的时候都会去判断机房的网络情况,如果网络出现中断,抑制其他报警防止报警泛滥:
# dc1的专线信号 0是0%丢包 1是100%丢包
dedicated_line_ping_loss{telecom="China Unicom",target="1.1.1.1",dc="dc1"} 0
dedicated_line_ping_loss{telecom="China Telecom",target="2.2.2.2",dc="dc1"} 0
# 判断专线是否故障
dedicated_line_ping_loss{} == 1
判断多条专线同时故障,只需要拿最小的专线查看即可
min(dedicated_line_ping_loss{}) == 1
但是当我们把这条规则作为Prometheus或VM-Alert的rules发现,只用min函数会丢失 telecom、target、dc等所有标签。
于是,我们必须要加上by操作
min by(telecom,target,dc) (dedicated_line_ping_loss{}) == 1
现在我们的表达式写完了,作为其他表达式的抑制条件可以这么写:
# 业务pod心跳丢失报警 1是存在 心跳丢失就是没有数据,假设我们已经通过服务发现能够实时获取到Pod名称
pod_heartbeat{pod_name="jwidsfjw-1"} 1
pod_heartbeat{pod_name="jwidsfjw-2"} 1
pod_heartbeat{pod_name="jwidsfjw-3"}
# 检测业务pod心跳丢失报警
absent_over_time(pod_heartbeat{pod_name="jwidsfjw-1"})
absent_over_time(pod_heartbeat{pod_name="jwidsfjw-2"})
absent_over_time(pod_heartbeat{pod_name="jwidsfjw-3"})
# 使用专线来抑制,防止专线故障时报警泛滥
absent_over_time(pod_heartbeat{pod_name="jwidsfjw-1"})
and on(dc)
min by(telecom,target,dc) (dedicated_line_ping_loss{}) == 1
这里可以看到,在最简单的单条件抑制情况下,整个表达式就已经不够直观了
使用RecordingRules简化
我们使用RecordingRules来简化一下实现
- name: dedicated_line_all_down
rules:
- record: dc:dedicated_line_all_down:min # 官方建议使用冒号来进行分割,具体规则是 目标:原指标名称:聚合方法
expr: min by(telecom,target,dc) (dedicated_line_ping_loss{}) default vector(0) # 使用default来保证这个指标查询不到的时候也能够打上value
labels: # 这里可以补充标签
上述规则生效后,我们便可从时序数据库中查询到名称 dc:dedicated_line_all_down:min{dc=”dc1”} 的线
上面的报警规则就可以直接使用这个新的指标,从而简化规则:
absent_over_time(pod_heartbeat{pod_name="jwidsfjw-1"})
and on(dc)
dc:dedicated_line_all_down:min{dc=”dc1”}
并且在大量报警规则都会用到 【机房网络断掉】这个指标的时候,就不用每次都进行min 计算了,因此也降低了时序数据库本身的计算压力,提高了查询效率。