为什么告警不能只是 if temp > 35:从零设计 IoT 告警引擎
在 iot-sim-gateway 项目中,我最初也以为告警就是"温度超了发通知"。直到亲手跑了一晚上仿真数据,才发现一个简单的阈值判断会产生多少噪音。这篇文章讲告警引擎的四个核心设计,以及踩过的坑。
1. 防抖(Debounce):3 次超限再报警
最早的代码是这样的:
if temperature > 35:
send_alert("高温告警")
跑了一晚上,收了 200 多条告警。点开一看——sensor-03 温度在 34.8°C 到 35.2°C 之间反复横跳,每次越过 35°C 就触发一条。
真实的传感器有量化噪声,一根信号线在阈值附近抖动是常态。解决办法是连续 N 次超限才确认告警:
self._breach_counters[key] = self._breach_counters.get(key, 0) + 1
if self._breach_counters[key] >= rule.debounce_count:
self._fire_alert(rule)
我把 debounce_count 设为 3,意味着温度必须连续 3 次超过 35°C 才触发。这样一来,偶然的噪声不会触发告警,真正的漂移会。
但这里有一个细节:计数器必须在值恢复正常时复位。
if self._is_breach(rule, value):
self._breach_counters[key] += 1
else:
self._breach_counters[key] = 0 # 关键:恢复正常,重新计数
不加这行会怎样?sensor-03 超了 2 次、回归正常、再超 1 次——计数器从 2 加到 3,触发告警。但这是两次独立事件,不应该合并计数。
2. 冷却(Cooldown):同一个问题不要反复报
防抖解决了误报,但带来了新问题——告警风暴。
sensor-01 从 25°C 漂移到 38°C 的过程中,每 2 秒发布一次数据。防抖要求 3 次连续超限,那么第 3、4、5 … 次触发后,告警引擎会连续发告警。
冷却机制:同一个设备、同一条规则,发过一次告警后 60 秒内不再重复。
def _can_alert(self, rule, key):
last = self._last_alerted.get(key, 0)
return (time.time() - last) >= rule.cooldown_sec
冷却期设为 60 秒,意味着漂移过程中只会收到 1 条高温告警,而不是十几条。
3. 趋势预判:别等出事了才说
防抖 + 冷却已经让告警靠谱了,但它有个根本问题——告知的是"已发生"而不是"将发生"。
温度已经超过 35°C 才报警,留给运维的反应时间是 0 秒。我加了一个趋势预判模块:取最近 60 秒的数据,用最小二乘法拟合斜率,预测多久会撞到阈值。
# 简单线性回归
slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
eta = (threshold - current) / slope
if eta > 0 and eta <= 300:
alert(f"温度持续上升,预计 {eta:.0f}s 后触达阈值")
面试跑回放的时候,Dashboard 上能看到趋势预判的倒计时——"预计 8s → 7s → … → 0s",然后阈值告警触发。从预警到告警有一条完整的时间线,比单纯报告"超了"有说服力得多。
局限:线性回归假设数据是线性的。如果传感器指数型恶化,斜率会低估。但 60 秒窗口内,线性近似够用。面试官问到这个的时候,能讲清楚"我为什么选择线性而不是多项式"——意味着你自己思考过。
4. 回放模式:演示不能赌概率
正常仿真下异常是随机触发的(drift 概率 0.2% / 每次 tick)。如果面试官等 5 分钟还没看到告警,演示就凉了。
我录了 4 个 JSON 场景,每个场景把数据点写死,30 秒必定走完"正常→异常→告警"的完整流程:
{"temperature": 25.0, "state": "NORMAL"},
{"temperature": 28.0, "state": "DRIFT"},
{"temperature": 33.0, "state": "DRIFT"},
{"temperature": 35.2, "state": "DRIFT"},
{"temperature": 37.9, "state": "DRIFT"}
面试官看到的是:Dashboard 上 temperature 从 25 → 38 一路涨,状态从绿色变黄色再变红色,趋势预判倒计时,最后 🔴 CRITICAL 弹出。
总结
告警引擎的演进路径:if temp > 35 → 防抖 → 冷却 → 趋势预判 → 回放演示。每一步都在解决上一步引入的问题。
核心代码在 gateway/alert_engine.py,168 行。面试能聊 10 分钟。
作者:[05zhijian] | GitHub: 05zhijian/iot-sim-gateway