分布式部署
先说结论:RuleGo-Server 独立部署(文件存储)是单实例设计——规则链、用户、设置、运行日志都落在本实例的数据目录里,副本之间互不可见,API 在副本 A 建的链不会出现在副本 B。真正的分布式部署不在 server 的 INI 里开关,而是由嵌入宿主提供共享存储与分布式锁。
本文给出两条已验证的路径,按你的场景二选一。
# 路径一(推荐):嵌入宿主实现分布式
适用:需要多副本负载均衡、数据集中存储、统一认证的业务平台。参考部署形态:GFlow 平台 (opens new window)(双实例 active-active,PG/MySQL),其审批引擎 GFlow Engine (opens new window) 开源。
宿主把 rulego-server 作为 Go 库嵌入,分三步接齐分布式能力:
# 第 1 步:共享存储(StoreProvider SPI)
实现 server/store 的 StoreProvider 接口(规则链/设置/组件/节点池/用户/运行日志六类存储),用你平台的关系型数据库承载:
provider := NewMyDBStoreProvider(db) // gorm/ent/sqlx 均可
app.New(
app.WithConfig(rgCfg),
app.WithStoreProvider(provider),
...
)
2
3
4
5
6
数据进了共享数据库,各副本读写同一份规则链,天然一致。
# 第 2 步:注入分布式锁(Config.Locker)
实现 types.Locker 接口(一般用 Redis),注入到 rulego 配置:
rgCfg.Locker = myRedisLocker // 类型:types.Locker
注入后所有用户引擎自动获得两类跨副本语义(原理见 至多一次执行):
- 定时端点去重:同一计划槽位整个集群只触发一次
- 广播端点单活选主:Redis Pub/Sub、RabbitMQ、MySQL CDC 端点只有主副本消费,主副本失联后待命副本自动接管
锁实现要求:键支持过期、Unlock 校验凭证(CAS);可选实现 LeaseRenewer 让主副本无窗口续约。扩展库有现成的 Redis 实现(支持单机/哨兵/集群):
import "github.com/rulego/rulego-components/pkg/locker"
rgCfg.Locker = locker.NewRedisLocker(redisClient)
2
3
# 第 3 步:触发源单投配置 + 认证接管
- 触发源本身支持分组的(Kafka 消费组、MQTT 共享订阅
$share/g/topic、NATS QueueGroup),配好分组即天然单投,无须任何锁 - 认证用
WithAuthenticator/WithAuthorizer接管(或DisableLocalAuth关闭本地账号),租户标识(Owner)会自动隔离锁键 - Redis 建议哨兵/集群部署;副本间保持 NTP 时钟同步
完整接入契约与多租户细节见 GFlow 平台 (opens new window)文档的 bridge 模块。
# 路径二(受限):只读同构副本
适用:规则链离线开发、打包进镜像、副本只消费不写入(如纯采集/转发的边缘集群)。
做法:所有副本挂载同一份只读数据目录(或镜像内置同一份 data 目录),触发源全部使用共享中间件的分组消费(Kafka 消费组、MQTT 共享订阅等,见 至多一次执行 的组件矩阵)。
限制必须清楚:
- 定时端点(
endpoint/schedule)每个副本独立计时,会重复触发——该形态下请避免定时链,或改走路径一 - API 建链不可用(写入只落在单副本)
- Redis Pub/Sub 等广播触发源需要单投时,只能靠触发源自身的分组能力,无锁可注入
# 部署检查清单(多副本)
- [ ] 存储已共享(路径一:StoreProvider;路径二:只读同构目录)
- [ ] 触发源配置了单投:Kafka 消费组、MQTT
$share共享订阅、NATS QueueGroup - [ ] 副本间 NTP 时钟同步
- [ ] Redis 高可用(路径一),Redis 不可用期间选主暂停、恢复后自动重选