🏦Rule-DB是什么
版本支持:v2.16.1+
Rule-DB是2.16.1推出的全新规则存储模式。在这个模式下,存储才是规则和脚本的权威源,JVM里常驻的只有规则清单、影子对象和状态索引,而EL正文、脚本源码和编译产物都放进有界缓存,按热度淘汰。
目前提供七个后端:
| 后端模块 | 存储 | 变更感知方式 |
|---|---|---|
liteflow-rule-db-sql | MySQL / MariaDB | seq 轮询(默认 3s)+ 周期对账 |
liteflow-rule-db-postgresql | PostgreSQL | seq 轮询 + 周期对账 |
liteflow-rule-db-mongodb | MongoDB(副本集/分片) | seq 轮询 + 周期对账 |
liteflow-rule-db-redis | Redis | seq 轮询 + 周期对账 |
liteflow-rule-db-zk | ZooKeeper | watch 实时推送 + 周期对账 |
liteflow-rule-db-etcd | Etcd | watch 实时推送 + 周期对账 |
liteflow-rule-db-nacos | Nacos(Server 2.x+) | Listener 推送 + 周期对账 |
# 和旧版规则配置源插件的区别
旧版的6个liteflow-rule-*插件(sql、zk、nacos、etcd、apollo、redis),本质上都是同一个流程:
启动 → 从存储全量读出所有规则和脚本 → 拼成一个大XML → 走同一条解析路径加载进JVM
存储在这里只是个"启动数据源",一旦启动完成,规则就活在各个节点自己的JVM里了。这么做有四个问题:
| 痛点 | 表现 |
|---|---|
| 多节点没有一致性保证 | 规则活在各节点的JVM里,刷新靠各插件自己的轮询或通知机制,时间窗内各节点的版本可能不一样。通知一旦丢了,也没有兜底的对账,最终收敛没法保证。 |
| 规则和脚本全量常驻JVM堆 | 即使开了parseOneOnFirstExec,EL文本和脚本源码还是全量待在FlowBus的map里。chainCacheEnabled只淘汰编译产物,不淘汰文本。规则一多,堆内存就上去了。 |
| 接入成本高 | 拿旧SQL插件来说,你得先建好表,再把每一个表名和字段名逐条映射进rule-source-ext-data-map,chainTableName、chainNameField、elDataField、scriptTypeField,二十来项,还得另外配轮询开关和周期。 |
| 写入全靠自己 | 没有官方的写入API,改规则就是往库里INSERT或UPDATE,版本号、指纹、刷新时机都得使用方自己拿捏。 |
Rule-DB把这几件事一并解决了:
- 存储是权威源,JVM只是缓存。发布和删除都走发布API,原子完成更新内容、版本号加一、写变更日志这三件事。所有节点靠变更通知和周期对账两条腿收敛,即使通知丢了,一个对账周期内也必然收敛。
- 规则正文和编译产物不再全量常驻。JVM仍然会为每条清单记录维护影子
Chain和Node、版本戳以及状态索引,这部分随规则总数线性增长;而EL文本、脚本源码和编译产物放进Caffeine有界缓存,按访问热度淘汰,淘汰之后退回影子状态,下次执行再懒加载。 - 配置基本上就一行。表结构和字段名都由模块固定,没有字段映射可配。对单数据源的Spring Boot应用来说,Rule-DB要的配置就是
spring.application.name,而这一行你本来就有。连接直接复用容器里的DataSource、RedissonClient、MongoClient、ConfigService,按类型自动查找,只有存在多个同类bean时才需要指名(zk的CuratorFramework和etcd的jetcdClient要显式配bean名)。 - 建表也可以免了。SQL和PostgreSQL开
auto-init-table=true,启动时就把四张表建齐;Redis的键结构在首次发布时自动创建;MongoDB的Collection和索引、zk和etcd的路径、Nacos的Catalog,都由Publisher初始化。整个上手过程里没有"先去数据库跑一段DDL"这一步。当然生产环境还是建议由DBA建表,好让执行账号保持只读。 - 改规则不用碰数据库。增删改都走统一的
RulePublisher,也就是publishChain、publishScript、removeChain、removeScript这几个方法。版本自增、md5重算、变更日志、发布顺序锁和乐观锁(expectedVersion),框架会在一个事务、一段Lua或者一次CAS里做完,发布之后各节点秒级收敛。管理后台只依赖一个jar,不需要拉起FlowExecutor。
一句话划清边界:旧的6个插件是二十来项字段映射加手写SQL改规则,启动时一次性灌库,之后各节点各跑各的;Rule-DB是一行配置加Publisher发布,存储永远是权威,JVM只缓存热规则,所有节点最终一致。
什么是影子状态
所谓影子状态,就是一个chain只注册了chainId,没有EL,也没编译;一个脚本Node只登记了元数据(type、language、name),没有源码,也没编译。这么做是为了让索引常驻、内容按需加载,执行到它的时候才回源拉取并编译。
# 旧插件还能用吗
能用,而且会继续维护,已有项目不需要为了升级2.16.1去改造。
但如果是新项目,我们推荐用Rule-DB。两者的运行模型和配置完全独立,不能混用:
liteflow.rule-source和liteflow.rule-db.*互斥,同时配置会启动报错。- 七个Rule-DB插件同一时刻classpath里只能有一个,启动时检测到多个会直接报错。
- 迁移到同一个后端时,旧的规则插件也要移除。
Apollo目前只有旧插件,Rule-DB的Apollo后端留作后续,core里的RuleRepository SPI已经定义好了。
# 它不管什么
Rule-DB只纳管EL和脚本,Java组件还是随应用代码一起部署。
Publisher只校验请求字段和存储约束,发布时不会编译EL。所以如果你引用了不存在的Java组件、子chain或脚本节点,是在执行节点首次编译这条chain的时候才会失败。
# 一致性语义(务必先读)
Rule-DB提供的是最终一致性,收敛窗口在秒级,它不是原子切换,也不是线性一致:
- 你发布一个新版本之后,在收敛窗口内,不同节点可能短暂地跑着不同版本。
- 正在执行中的请求会持有旧的条件树引用跑完,新的执行拿到新版,这和现有的copy-on-write语义一致。也就是说,不会所有节点在同一个逻辑时刻切换。
- 对绝大多数业务编排场景来说这已经够了。但如果你的业务要求全集群在同一时刻切版,那么当前版本的Rule-DB满足不了,请不要用。
详见一致性与收敛模型。



