为什么告警不能只是 if temp > 35:从零设计 IoT 告警引擎

21 阅读3分钟

为什么告警不能只是 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