时序数据规则引擎设计思路
规则引擎的大致组成包括:
- 触发条件:如某个设备某种消息在某个时间点内到达;或周期性,每隔多久触发一次;
- 触发响应:即触发条件后要做什么,一般是告警、通知、联动其他设备、联动其他系统等;
- 边界情况:重复触发如何处理、回调频率控制等细节;
实现思路大致包括以下几种:
基于消息回调
即在消息到达服务器时,执行指定回调。常见的有webhook、执行脚本文件(如js)、或执行java的jar包等等。
该方案在消息频繁触达时性能较差,并且容易造成重复计算,但是理论上也能满足一般的计算需求。回调方可以调用数据接口查询相关的数据做任意运算,再根据结果来触发告警或其他行为。
目前墨斗平台内置的规则引擎即基于此架构,不过触发响应是写死的几种,还不包括上面这些更灵活的方式。理论上来说,客户基于rabbitmq自己订阅消息来实现对应的逻辑也是一样的。
基于周期性计算
比如kibana、zabbix等,使用SQL或其他DSL创建告警条件,服务器会周期性地运行这些条件,判断满足则触发动作。
上图是kibana的一个基于日志等级预警的例子,可以看出来其实大概就是select count(*) from logs-golang* where log.level='ERROR' and ts > now()-1m
的结果与1进行比较的意思。
每分钟运行上述规则一次,即可以判断是否发生预警。
数据先入库,然后再定时计算,这样做的好处是架构比较简单,基于SQL或类SQL的DSL来写表达式即可,同时可以提供类似上面的图形界面,用于简化配置,对于使用者的要求不高。坏处是不够即时,kibana这里要求间隔至少是1分钟1次,所以告警可能会延迟1分钟。此外,频繁的周期性调度,对性能影响也比较大。
此外,这种方式计算的数据并不会入库。当然如果是时序数据,可以基于ts定时计算后再入库,因为时序数据是不变的。如果是一般的数据,需要计算入库就必须用流式计算来进行了。
基于实时流计算
即类似FlinkCDC的思路来做。thingsboard的规则引擎是基于消息到来时进行触发,但是只能处理单条消息,没有使用时间窗口技术,所以是个半成品。真正的流计算必须使用类似Flink的时间窗口技术,并允许跨多条消息进行处理。
与基于消息回调不同,实时流计算可以将需要计算的数据缓存在内存中,通过时间窗口来维护变量的生命周期,其性能比回调时去查询数据库要高的多。
Flink支持CEP功能,但是不支持动态规则更新(FLIP-200),如果使用阿里云商业的Flink,可以考虑使用该功能。
除了Flink,还有siddhi、esper和drools等方案,但是都有一些问题。
选型 | 优点 | 缺点 |
---|---|---|
drools fusion | 同上,语法drl | 不支持集群 |
esper | 支持嵌入式运行(即作为一个库)java语言,符合公司技术栈类似SQL的语法 | 集群是收费功能 |
Flink-CEP | 性能最好,也最灵活 | 需要二次开发,不支持动态更新规则(FLIP-200)没有用户友好界面 |
siddhi | 比较轻量级,自带图形界面可以编排规则 | 不是很活跃,性能未知 |
lite-flow | java嵌入式运行,规则可以持久化到数据库,支持动态刷新规则,支持常用脚本语言,中文文档齐全 | 前端需要自行开发 |
这里个人推荐lite-flow,功能比较健全,配合脚本功能可以满足大部分需求。
建议实施步骤
基于单条数据的实时处理、或回调触发最为简单,可以优先实现,满足5成以上的需求;
基于周期性计算的规则引擎更容易图形化,实现起来也相对简单(但是要采用一种DSL),非即时计算的场景可以采用该方案;
基于CDC的方案最为灵活,但是对使用者的要求较高,实现起来也有一些技术难度,在对实时性要求极强的场景下可以采用该方案;