告警风暴的收敛设计:去重、聚合与抑制
支持四象限运行、采用 FOC 驱动方式的 AQMD6008BLS-TE/2 这类设备批量部署后,最容易失控的不是数据量,而是告警量。一次阈值抖动或一个共性缺陷,能在几分钟内产生成千上万条告警,把真正的问题埋掉。
一、风暴的三个来源与量级
取 500 台设备(示例值):
| 来源 | 触发场景 | 告警量估算 | 根因 |
|---|---|---|---|
| 阈值抖动 | 温度在 85℃ 阈值附近波动 | 每台每天可达数百条 → 数万条 | 无滞回、无持续时间 |
| 共性缺陷 | 某批次参数错误导致过流 | 500 台同时告警 | 无灰度、无关联 |
| 规则重复 | 多条规则命中同一事件 | 放大 2~5 倍 | 规则未分层 |
三类成因对应不同手段,混用一种方法解决不了全部。
二、四层收敛手段
第一层:滞回 + 持续时间。 阈值上下分开,并要求越限持续一段时间才告警,能消掉绝大部分抖动。
第二层:指纹去重。 用 设备 + 故障码 + 时间桶 生成指纹,同一指纹在窗口内只发一次,后续只累加计数。
第三层:聚合。 同一故障码在窗口内跨设备合并为一条"影响 N 台"的聚合告警,运维看趋势而不是逐台刷屏。
第四层:抑制与升级。 父级告警(如"网关离线")抑制其子设备告警;连续多次聚合再升级为高优先级,避免一开始就全员打扰。
/* 滞回 + 持续时间:越限需持续 hold_ms 才触发,回落低于 lo 才复位 */
typedef struct {
float hi, lo, hold_ms; uint32_t since; uint8_t armed; } al_t;
int alarm_eval(al_t *a, float v, uint32_t now_ms)
{
if (!a->armed) {
if (v > a->hi) {
if (a->since == 0) a->since = now_ms;
if (now_ms - a->since >= a->hold_ms) {
a->armed = 1; return 1; } }
else a->since = 0;
} else if (v < a->lo) {
a->armed = 0; a->since = 0; }
return 0;
}
/* 指纹去重:同 code 在 window 内只上报一次,其余累加 */
typedef struct {
uint32_t code, last_ts, count; } fp_t;
int fp_allow(fp_t *f, uint32_t code, uint32_t now_s, uint32_t window_s)
{
if (f->code == code && now_s - f->last_ts < window_s) {
f->count++; return 0; }
f->code = code; f->last_ts = now_s; f->count = 1;
return 1;
}
三、告警必须可回溯
收敛不等于丢弃。被抑制的告警要落到明细存储(可低优先级、可短保留期),聚合告警里带上"明细查询入口"与样本设备列表,否则事后无法还原影响面。同时记录每条告警的规则版本与阈值,便于复盘"是不是阈值设错了"。
四、验证方法
一是风暴注入:让 500 台模拟设备在阈值附近波动 10 分钟,统计收敛前后的告警条数与压缩比;二是抑制正确性:制造网关离线,确认子设备告警被抑制且网关告警保留;三是回溯演练:任选一条聚合告警,确认能查出全部明细与样本设备。
五、小结
告警风暴按成因分三类(抖动、共性缺陷、规则重复),对应四层手段:滞回+持续时间、指纹去重、跨设备聚合、父子抑制与升级。收敛必须保留明细可回溯并记录规则版本,用风暴注入、抑制正确性、回溯演练三类测试闭环。