ShardingSphere的新一代Zookeeper注册中心实现剖析

3次阅读

共计 3734 个字符,预计需要花费 10 分钟才能阅读完成。

作者介绍

李东博

厚泽贷系统架构师

二次元资深宅

原本是做.net 的,跟着公司转型误打误撞开始做互联网,做着 JAVA 架构的工作,干着运维的活。对逻辑和技术感兴趣,希望能在这条路上越走越远。对未知的技术方向有很强的好奇心,包括开源框架的实现,以公司架构选型为契机接触了 sharding sphere 社区,如果能在对社区参与中不断提升自己也是很好的。


最近的业余时间多用于做这件事:

https://github.com/sharding-s… 

由于是以完成现有功能为目标的,同时业余时间也不太充足,所以其中有些用不到地方处理的有些粗糙,另外还有原本打算用上,但最后没用上的,还有干脆就没做的部分,比如 zk 的一些一步回调执行的接口。我打算在这里把开发的过程,思路介绍一下,大家如果有兴趣,大家一起来把它做好。

组成结构

包结构

开发细节

Holder

UsualClient 的基类 BaseClient 中有一个比较重要的类型 Holder,因为没有顺眼的地方现在放在 base 包里。

最开始是没有这个类型的,zk 的连接由 BaseClient 维护,但是在做重试功能的时候觉得怎么实现怎么别扭,因为重试功能按说是在 Client 内部实现,但是如果连接由 Client 维护,那重试策略势必要操作 Client,这引用关系就相当凌乱了。而且由于先做的异步重试(其实同步重试一样),在重试过程中会涉及到连接和监听,如果传递 Client,重试的 Operation 立场就会十分尴尬。

于是,根据书上有别扭就必然是因为有隐含的概念没有抽取出来的理论,寻找一个合适解耦的中间层抽取出来,那就比较明显了。把 zk 连接的维护独立出来,Client 中只负责对节点的操作,由 Holder 来维护节点连接。同时在 Client 中创建 Provider 实例的时候可以把 Holder 实例传递给 Provider,这样重试策略 Provider 就完全 hold 得住了。

Watcher

Holder 里还有一个比较重要的部分是 Watcher。一般情况下 zk 原生的 Watcher 功能只能使用一次,不过有一个地方除外,就是 new 的时候通过 zk 构造传进去的那个 Watcher,由于是用于监听连接状态的,所以一直存在。于是我就通过 Client 提供一个 registerWatch 方法,把注册的监听放到一个 Map 里,有新的 event 的时候会遍历 Map 执行监听,此处有一个需要完善的地方,就是遍历 Map 时候的判断,现在只是简单的判断了路径为 null 或者匹配,并没有根据对应的事件类型过滤监听器,这个后续一定会有过滤的需要。这里看代码会发现还有个全局监听,主要是在测试的时候用的,什么事件都会走一遍。

Context

另外 Client 里会看到有 Context 的使用,但是其实这玩意是做重试功能时候,怎么试怎么不顺眼,就拿来传参数用了,其实抽出 Holder 以后我本来是有想法把它去掉的,不过看着也不太讨厌就留下了,如果能优雅的去掉,我也是欢迎的。

BaseClient

BaseClient 主要功能有 start、close、注册、认证和创建删除根节点。start 这有一个 blockUntilConnected 方法,主要功能是如果在一定时间内启动不成功就返回启动失败。这个方法是在 curator 同名方法上稍微简化了一下,我比较不喜欢这种实现方式,holder 里实现的 start 是用 CountDownLatch 阻塞的,CountDownLatch 的 await 本身就有时间参数的重载,我现在在准备用 await 的重载方法替代 blockUntilConnected,功能是没问题了,只是两个单元测试出现了互相影响的现象,还没调好。创建和删除根节点是为了实现 namespace 的功能的,使用 namespace 做根节点,不同的 namespace 下的节点就不会互相影响了。

同步重试策略

现在注册中心的 Client 使用的执行策略是同步重试 SyncRetryStrategy,是用 Callable 实现的。Callable 会从 section 包移到 retry 包里去的。主要逻辑就是根据延迟策略创建延迟策略的执行者,每次执行失败先判断失败的异常是否是需要重新连接 zk server 的,如果是 resetConnection 后延迟重试,否则直接延迟重试期待延迟过程中 zk 自动重连,之后由执行者判断是否还有下一次执行。这里有一个暂时没有场景所以先没处理的地方,就是只支持延迟策略,需要抽象一个策略基类,并且支持更多的重试方式。

异步重试策略

异步重试策略 AsyncRetryStrategy 是由 AsyncRetryCenter 执行的,在该策略的 api 执行时,如果捕捉到需要重试的异常,就创建当前操作的对象加入到延迟队列中。操作类的基类 BaseOperation 派生自 java.util.concurrent.Delayd,并且与上面的同步重试一样都是使用延迟策略的执行者来判断下一次执行的。DelayQueue 的消费是在 RetryThread 中。

先跑个题,这里可以看到有一些常数,其实是应该抽出来了,utility 包里还有一些常量,虽然目前没什么用,不过其实是应该做成配置文件的。

接着说消费,消费就是一个 for (;;) 不停的 take,take 出来提交给线程池执行,这里使用线程池是防备会在一个时间节点有很多个操作到期,我测试 zk 3.3.x 版本时发现连接失败是比较容易出现的。

竞争策略

然后说竞争策略 ContentionStrategy 和 TransactionContentionStrategy,竞争的逻辑在抽象类 LeaderElection 中,就是竞争者发起创建一个临时节点的请求,如果报 NodeExistsException 就注册一个该临时节点删除的事件监听,一旦监听触发就再次发起创建请求直到成功。这里有两个 todo,一是创建节点的时候并没有使用节点序列号,如果需要选举功能,这一点是需要的;另外一个是目前只对根节点竞争,并不是对指定节点,这也需要补完。

BaseProvide

BaseProvider 里不止有草图中说的拆分事务专用 Provider,还有一个比较大的事没做,就是 zk 的回调类 api,我是准备增加一个 ICallbackProvider 的接口,如:

将 zk 事务和非事务分成两个是因为没事务的部分是可以支持全版本的 zk,我排除掉事务测试过 3.3.0 开始的所有版本都可以支持。但是事务是 3.4.0 才有的功能。ZKTransaction 也是为了排除事务方便做的包装。

缓存

CacheStrategy 是因为最开始使用的是定时启动线程全量的缓存数据更新,但是后来感觉直接根据订阅的事件更新更好,于是就两种都留下来了。PathStatus 是用来在更新的时候判断是否有正在执行的其他更新用的。

缓存的主要功能是由 PathTree 和 PathNode 实现的。PathTree 里有一个根节点,节点是 PathNode 类型,用了 Map<String, PathNode> 保存子节点,与 zk 的逻辑结构对应(我有时候在想这里是不是应该直接抄 zk,回头了解一下),其他就是实现了 CRUD。这里要说的是获取节点的 get 是用了个 Iterator 对深度做迭代了,这里其实用 sharding 语法解析的那个 token 感觉更好,其实最开始是类似思路做的,但是写的不顺眼就改成这样了,之后是想参考语法解析的部分改了这个 get 的。里面还有个 todo,就是那里代码不顺眼。定时全量更新缓存是调用 refreshPeriodic 就可以了。订阅更新的话代码是 watch 方法,这个 watch 方法的调用我也感觉有些别扭,一定得先调用 load 之后跟着调用 watch,可能没描述清楚,但是借助 IDE 的查找所有引用应该能明白我的意思。

版本号

最后还有一个非常大,但平时没怎么用过的功能,就是版本号,zk 的 api 是有版本号差异的,虽然目前用的代码里并没有用上这个特点,但是不做总是不完整的,而且未来也未必用不上,版本号的维护在大量高频的对 zk 的写时是很必要的,这一点后面是要重点做的。

除了以上列出的这些,应该还是有其他不完善的地方,希望大家也能和我一起做好它。当然,也不止是这一部分,大家贡献自己的一点力量,sharding-sphere 发展的更好,同时对自己的提升也是很有帮助的。


Sharding-Sphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar 这 3 款相互独立的产品组成。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。

亦步亦趋,开源不易,您对我们最大支持,就是在 github 上留下一个 star。

项目地址:

https://github.com/sharding-s…

https://gitee.com/sharding-sp…

更多信息请浏览官网:

http://shardingsphere.io/

或加入 Sharding-Sphere 官方讨论群

感谢您的支持与关注

我们将不忘初心,不负众望!

正文完
 0