2、告警规则引擎:规则链中的告警节点、创建告警规则、告警类型与严重级别配置

好,咱们接着聊告警。上一章我们把告警的基础概念和整体架构理清了。这一章,我带你深入 ThingsBoard 的规则引擎,看看告警到底是怎么被“生产”出来的。

说白了,告警不是凭空产生的。它需要一套规则来定义:什么时候触发?触发了算什么级别?消息里带什么信息?这些,都得靠规则链里的告警节点来完成。

2.1 规则链中的告警节点:告警的“加工厂”

在 ThingsBoard 里,规则链就像一条流水线。数据流进来,经过一个个节点处理。而告警节点,就是这条流水线上专门负责“生产告警”的工位。

我个人习惯把告警节点分成两类:创建/更新节点清除节点。它们俩通常是成对出现的。

2.1.1 创建告警节点(Create Alarm Node)

这个节点是核心。它的作用就是:根据传入的消息,生成一条告警记录。

你想想看,一条遥测数据进来了,比如温度传感器报了 85 度。创建告警节点会检查这条数据,如果符合你设定的条件,它就“啪”一下,生成一条告警。

配置这个节点时,有几个关键字段你得搞清楚:

  • 告警类型(Alarm Type):这是告警的“身份证”。比如“高温告警”、“设备离线告警”。同一个类型的告警,在同一个设备上只会存在一条活跃的。
  • 告警严重级别(Severity):就是告警的“严重程度”。后面我会细说。
  • 告警消息(Alarm Message):告警的具体描述。你可以用模板,比如 ${entityName} 温度过高,当前值: ${temperature}
  • 告警详情(Alarm Details):一个 JSON 对象,可以存一些额外的结构化数据。比如当前的具体数值、触发时间戳等。

核心要点: 创建告警节点是“幂等”的。什么意思?如果同一个设备、同一个告警类型已经有一条活跃告警,新的触发不会创建新告警,而是会更新已有告警的详细信息(比如更新最后触发时间、累计次数)。

2.1.2 清除告警节点(Clear Alarm Node)

有创建,就得有清除。这个节点负责把活跃的告警标记为“已清除”。

我在项目中遇到过一种情况:设备温度恢复正常了,但告警一直挂着,运维人员天天被骚扰。后来我加了一个清除节点,当温度低于某个阈值时,自动清除对应的“高温告警”。世界清净了。

清除节点通常和创建节点配合使用。它的配置相对简单,只需要指定要清除的告警类型,以及匹配条件。

注意: 清除节点不会删除告警记录,只是把状态从 ACTIVE_UNACKACTIVE_ACK 改为 CLEARED_UNACK。历史数据是保留的,方便事后复盘。

2.2 创建告警规则:从数据到告警的“翻译官”

光有节点还不够,你得告诉节点“什么时候干活”。这就是告警规则的作用。

告警规则,本质上是一个过滤器 + 转换器。它写在创建告警节点的配置里,通过脚本或条件表达式来定义。

我常用的方式有两种:

2.2.1 基于脚本的规则(TBEL)

ThingsBoard 有自己的表达式语言,叫 TBEL。它很灵活,适合复杂的逻辑判断。

举个例子,我想对温度传感器设置一个规则:如果温度连续 3 次超过 80 度,才触发告警。用脚本可以这么写:

// 检查消息类型
if (msg.temperature != null) {
    // 获取当前设备的历史告警上下文
    var alarmDetails = metadata.alarmDetails;
    var count = alarmDetails ? alarmDetails.count : 0;
    
    if (msg.temperature > 80) {
        count = count + 1;
    } else {
        count = 0; // 温度降下来就重置计数
    }
    
    // 更新上下文,供下次使用
    metadata.alarmDetails = { count: count };
    
    // 只有计数达到3次才真正创建告警
    return count >= 3;
}
return false;

你看,这里用到了 metadata.alarmDetails 来存储中间状态。这是 ThingsBoard 提供的一个小技巧,可以跨消息传递数据。

我的经验: 脚本里尽量别写太复杂的逻辑,否则后期维护起来很头疼。我一般把脚本控制在 20 行以内,超过这个数,我会考虑拆成多个规则链节点。

2.2.2 基于条件的规则(简单模式)

如果你不想写脚本,ThingsBoard 也提供了图形化的条件配置。你可以直接选择“大于”、“小于”、“等于”等操作符。

比如:

  • 条件:temperature > 85
  • 告警类型:High Temperature
  • 严重级别:CRITICAL

这种方式适合简单的阈值告警。但说实话,稍微复杂一点的场景,比如“连续 N 次超过阈值”,还是得靠脚本。

2.3 告警类型与严重级别配置:给告警报个“身份证”和“红黄牌”

告警类型和严重级别,是告警的两个核心属性。配置得好,运维人员一眼就能看出问题在哪、有多严重。

2.3.1 告警类型(Alarm Type)

告警类型是一个字符串,用来区分不同种类的告警。它通常和设备类型、业务场景相关。

我建议你遵循一个命名规范:名词 + 动词。比如:

  • DEVICE_OFFLINE:设备离线
  • BATTERY_LOW:电量低
  • TEMPERATURE_HIGH:温度过高
  • CONNECTION_TIMEOUT:连接超时

为什么要规范命名?因为告警类型会出现在告警列表、通知消息、甚至第三方系统的集成中。命名混乱,后期查问题会非常痛苦。我曾经接手过一个项目,告警类型有“高温”、“温度高”、“temp_high”三种,其实都是同一个意思。嗯,那段时间我花了不少时间做数据清洗。

2.3.2 严重级别(Severity)

ThingsBoard 内置了三种严重级别:

级别 颜色 含义 典型场景
CRITICAL 红色 致命问题,需要立即处理 设备离线、温度超过安全阈值、数据丢失
MAJOR 橙色 重要问题,需要尽快处理 电池电量低、性能下降、连接不稳定
MINOR 黄色 一般问题,可以稍后处理 轻微超限、配置变更、周期性维护提醒

你可能会问:只有这三种吗?能不能自定义?

答案是:不能直接自定义。ThingsBoard 的告警系统只支持这三种级别。但你可以通过告警详情(Alarm Details)里的字段来模拟更细的级别。比如加一个 subSeverity 字段,值为 1 到 10。

避坑指南: 我曾经把 CRITICAL 级别用得太随意了。结果运维人员对红色告警麻木了,真正出大事时反而没人重视。我的建议是:CRITICAL 只留给那些需要人工立即介入的场景,比如设备完全失联、数据严重异常。其他情况,能用 MAJORMINOR 就别用 CRITICAL

2.4 实战配置示例:一个完整的告警规则链

说了这么多,咱们来动手配一个。假设我有一个温度传感器,我希望:

  1. 温度超过 80 度时,创建一条 MAJOR 级别的告警。
  2. 温度超过 90 度时,升级为 CRITICAL 级别。
  3. 温度回落到 75 度以下时,自动清除告警。

规则链的设计思路是这样的:

  • 入口节点接收遥测数据。
  • 经过一个“脚本过滤器”节点,判断温度值。
  • 根据温度范围,路由到不同的“创建告警”节点。
  • 再经过一个“清除告警”节点,判断是否需要清除。

在创建告警节点的配置里,我会这样写:

// 创建告警节点配置(针对 CRITICAL 级别)
{
  "alarmType": "HIGH_TEMPERATURE",
  "severity": "CRITICAL",
  "alarmMessage": "设备 ${entityName} 温度极高!当前值: ${temperature}°C",
  "alarmDetails": {
    "threshold": 90,
    "currentValue": "${temperature}",
    "timestamp": "${ts}"
  }
}

清除节点的配置就简单了:

// 清除告警节点配置
{
  "alarmType": "HIGH_TEMPERATURE",
  "clearCondition": "return msg.temperature < 75;"
}

你看,整个流程很清晰。数据进来,判断,创建或清除。这就是告警规则引擎的核心工作方式。

小技巧: 在开发阶段,我习惯在规则链里加一个“日志”节点,把告警节点的输入输出都打印出来。这样调试起来非常方便,能快速定位是条件写错了,还是数据格式不对。

好了,这一章的内容就到这里。告警规则引擎是 ThingsBoard 告警系统的“大脑”,理解了它,你就能灵活地控制告警的生成逻辑。下一章,我们聊聊告警通知——怎么把告警消息推送到你的手机、邮件或者钉钉上。