3、报警规则引擎:规则引擎架构、规则定义语法、规则优先级与冲突解决
规则引擎这东西,说白了就是报警系统的「大脑」。没有它,你收到的报警要么铺天盖地,要么该来的不来。我见过太多团队,监控数据采了一大堆,结果规则写得一塌糊涂,最后运维同学天天被报警轰炸,反而把真正重要的信号淹没了。
这一节,咱们就聊聊规则引擎到底怎么搭,规则怎么写才靠谱,以及多个规则打架时怎么处理。
3.1 规则引擎的核心架构
先看一张整体架构图,帮你建立直观印象。
整个流程其实不复杂。数据先进来,然后规则引擎把咱们写的「人话规则」编译成机器能快速匹配的内部结构。接着就是匹配、仲裁、执行。
我个人习惯把规则引擎拆成四个核心模块:
- 规则加载器:从文件、数据库或配置中心拉取规则定义。支持热加载很重要,你总不想改个阈值还要重启服务吧?
- 规则编译器:把 YAML 或 JSON 格式的规则,编译成内存中的 AST(抽象语法树)或 RETE 网络。这一步决定了匹配效率。
- 匹配引擎:拿着实时数据,跟所有已编译的规则做比对。这里最核心的是「时间复杂度」—— 规则越多,匹配越慢。
- 动作执行器:匹配成功后,执行通知、自愈、升级等动作。注意,动作本身也可能失败,要做好重试和降级。
3.2 规则定义语法
规则怎么写,直接影响后续的维护成本。我见过最离谱的规则,是用 Shell 脚本拼出来的,每次改规则都要上线发布…… 那画面太美我不敢看。
这里给出一套我常用的规则定义结构,用 YAML 表示:
# 报警规则示例
rules:
- name: "CPU使用率过高"
id: "rule_cpu_001"
description: "当CPU使用率连续3分钟超过90%时触发"
enabled: true
# 数据源
source:
type: "prometheus"
query: "avg by(host) (cpu_usage_percent)"
interval: "30s"
# 触发条件
condition:
type: "threshold"
operator: "gt"
value: 90
duration: "3m" # 持续3分钟才触发,避免毛刺
aggregation: "avg" # 取平均值
# 优先级
priority: 1 # 1最高,5最低
# 动作
actions:
- type: "notification"
channels: ["email", "wechat"]
template: "主机 {{.host}} CPU使用率 {{.value}}%,已持续 {{.duration}}"
- type: "escalation"
after: "10m" # 10分钟后未恢复,升级通知
to: ["oncall-leader"]
# 依赖关系
dependencies:
- "rule_network_001" # 如果网络规则已触发,本规则降级
关键字段说明:
| 字段 | 说明 | 我的建议 |
|---|---|---|
| condition.type | 条件类型:threshold / change / anomaly / expression | 能用 threshold 就别用 expression,越简单越不容易出错 |
| condition.duration | 持续时长,用于防抖 | 至少设 1-3 分钟,别让瞬时毛刺炸你手机 |
| priority | 1-5 级,1 最高 | P0 给 1,P3 给 4,别全设成 1 |
| dependencies | 规则间的依赖关系 | 这个很多人忽略,但它是解决「报警风暴」的关键 |
3.3 规则优先级与冲突解决
规则多了,冲突是必然的。比如:
- 规则 A 说「CPU > 90% 发 P0 报警」
- 规则 B 说「CPU > 95% 且持续 5 分钟才发 P0,否则只发 P2」
两条规则同时匹配时,听谁的?
3.3.1 优先级设计
我一般用「数值越小优先级越高」的方案:
| 优先级 | 含义 | 典型场景 |
|---|---|---|
| P0 (1) | 核心业务中断 | 支付链路中断、数据库主从切换失败 |
| P1 (2) | 主要功能受损 | API 延迟 > 5s、订单积压 |
| P2 (3) | 非关键异常 | CPU > 80%、磁盘使用率 > 85% |
| P3 (4) | 告警通知 | 证书即将过期、备份完成 |
| P4 (5) | 信息记录 | 日常巡检报告、版本发布通知 |
优先级决定了三件事:
- 通知的紧急程度:P0 直接打电话,P4 发个邮件就行
- 展示排序:高优先级的报警永远排在最前面
- 冲突时的裁决依据:高优先级覆盖低优先级
3.3.2 冲突解决策略
冲突解决,说白了就是「当多条规则同时匹配时,到底执行哪条」。我常用的策略有四种:
| 策略 | 规则 | 适用场景 |
|---|---|---|
| 优先级优先 | 只执行优先级最高的规则 | 大多数通用场景 |
| 合并执行 | 所有匹配规则都执行,但按优先级排序 | 需要多维度通知时 |
| 互斥组 | 同一组内的规则,只执行一条 | 同一指标的不同阈值规则 |
| 依赖降级 | 如果依赖规则已触发,本规则降级或静默 | 防止报警风暴 |
我的实战方案: 我习惯用「优先级优先 + 互斥组」的组合。比如 CPU 相关的规则放在一个互斥组里,组内按优先级执行。这样既避免了重复报警,又保证了最高优先级的规则一定被执行。
3.3.3 一个真实的冲突案例
之前帮一家电商公司优化报警系统,遇到一个典型冲突:
- 规则 A:订单接口错误率 > 1% 发 P1 报警
- 规则 B:订单接口错误率 > 5% 发 P0 报警
当错误率冲到 8% 时,两条规则同时匹配。原来的系统两条都执行,结果运维收到两条报警,一条 P0 一条 P1,反而搞不清到底多严重。
我的解决方案:把这两条规则放进同一个互斥组,组内按优先级执行。错误率 8% 时,只执行 P0 那条。同时,在 P0 的报警内容里附带一句「已超过 P1 阈值 8 倍」,信息量反而更足。
3.4 规则引擎的性能考量
最后聊几句性能。规则引擎跑得慢,报警就滞后,那还不如不报警。
几个关键指标:
- 匹配延迟:从数据到达规则引擎,到输出匹配结果。我一般要求 < 50ms。
- 规则加载时间:热加载时,不能影响正在执行的匹配。建议用双缓冲池。
- 内存占用:每条规则编译后大概占 1-5KB,2000 条规则也就 10MB,不是瓶颈。
嗯,规则引擎这块,核心就是「架构清晰、语法规范、冲突有解」。你把这三点拿捏住了,报警系统就稳了一大半。