摘要
本节讲讲通过watcher机制实现casbin多节点策略数据的同步。上节分析casbin源码的时候有讲到watcher是以插件的形式注册进来的,并且github上有基于etcd,redis,kafka,ZooKeeper,RocketMQ,RabbitMQ等各种中间的watcher,为了选定一个最适合的watcher,就务必要熟悉各类中间件之间的优缺点及他们适用的场景。
消息中间件
redis
redis我们都知道,有着丰富的数据类型以及高效的读写速度,非常适合用来做缓存组件。同时主从复制,哨兵模式,集群模式功能等也保证了redis的高可用性。但是redis 没有ack机制,数据可靠性难以保证,要自定义数据持久化,否则断电后数据丢失。相比于kafka之类的中间件redis不支持消费分组,也就无法做消费端的负载均衡
etcd
etcd的优点也是非常明显,一是足够简单,操作快每秒支持10000次写操作,二是基于raft一致性算法,各节点之间保持高度一致并且足够安全可以选择SSL客户认证机制,也支持典型的消息发布订阅模式。但是缺点就是数据结构单一(仅支持key:value),大规模应用场景有限,目前etcd在构建分布式系统时通常应用于服务发现,分布式配置中心等场景
kafka
kafka依赖于ZooKeeper(比如broker注册、topic注册、producer 和 consumer 负载均衡、维护 partition 与 consumer 的关系、记录消息消费的进度以及 consumer 注册等)kafka常用于系统之间削峰,解耦,并且kafka最初是被设计为一个分布式的日志系统,因此其吞吐率非常的高,同时对TB级以上的数据也能保证常数时间的访问性能,并且支持水平扩展,消费负载均衡等。显然kafka相对而言较为“笨重”,所以对于casbin节点之间同步的策略数据不是非常大的情况下kafka就显得有点大材小用了
ZooKeeper
ZooKeeper是一个典型的发布/订阅模式的分布式数据管理与协调框架,功能也比较强大,能应用的场景也比较多,相比于kafka ZooKeeper还能保证写操作的严格顺序性,但Zookeeper有严格的节点限制。通过Zab协议保证集群之间的数据一致性,而非常规的raft协议,所以相比于我们熟知的redis和足够简单的etcd,ZooKeeper也显得没那么的友好。
基于redis的casbin watcher
对于casbin节点之间策略数据同步没那么频繁的,可以直接借助redis的 消息发布/订阅机制,实现各节点之间策略数据的增量同步。实现代码我已同步到github上:github.com/KDKYG/casbi… ,几个优化点值得注意:
1.为保证各节点之间足够快的同步到策略数据,要谨慎选择adapter(既casbin策略数据的持久化实现),如果我们的策略决策数据可以依据业务数据而生成的话,甚至可以去除掉adapter,因为从上章分析casbin源码的时候,可以看到在AddPolicies的时候,如果有adapter会把策略数据也添加到adapter,所以adapter必然会影响到策略数据的同步速度,有可能我们的策略数据还没在当前节点同步完,下一个请求就打到当前节点来了,这样就会影响业务
2.开源的go-redis实现上,默认指定的频道大小是100,所以为防止同步的消息过多打满channel,在进行策略数据发布的时候必须批量发布,不要一条一条的进行发布,如果项目的qps较高,建议可以搭建redis集群承载足够多的写操作
3.通过casbin的源码可以发现,在并发添加策略数据的时候其实是不安全的,那同样的在订阅频道获取策略数据进行添加和本地的添加两个操作要保持互斥,同时在订阅了频道的策略数据进行添加的时候,要避免再次触发redis的发布订阅机制把相同的消息又同步到各节点,这样会陷入死循环。所以要实现自己的并发安全的Enforcer,订阅到策略数据准备添加前 加锁,同时关闭notifyWatcher开关,添加完后打开开关释放锁。如下: