我随意写,你随意看。

林老头儿

但愿绝望和无奈远走高飞

Fork me on Gitee

ZkClient的使用

简介

ZkClient 是由 Datameer 的工程师开发的开源客户端,对 Zookeeper 的原生 API 进行了包装,实现了超时重连、Watcher 反复注册等功能。

在使用 ZooKeeper 的 Java 客户端时,经常需要处理几个问题:重复注册 watcher、session失效重连、异常处理。

目前已经运用到了很多项目中,知名的有 Dubbo、Kafka、Helix。

使用

1)Maven依赖

<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>

2)ZkClient 的设计

从上述结构上看,IZKConnection 是一个 ZkClient 与 ZooKeeper 之间的一个适配器。在代码里直接使用的是 ZKClient,其实质还是委托了 zookeeper 来处理了。

使用 ZooKeeper 客户端来注册 watcher 有几种方法: 1、创建 ZooKeeper 对象时指定默认的 Watcher,2、getData(),3、exists(),4、 getchildren。其中 getdata,exists 注册的是某个节点的事件处理器(watcher),getchildren 注册的是子节点的事件处理器(watcher)。而在 ZKClient 中,根据事件类型,分为了节点事件(数据事件)、子节点事件。对应的事件处理器则是 IZKDataListener 和 IZKChildListener。另外加入了 Session 相关的事件和事件处理器。

ZkEventThread 是专门用来处理事件的线程。

3)重要处理流程说明

  • 启动 ZKClient

  • 在创建 ZKClient 对象时,就完成了到 ZooKeeper 服务器连接的建立。具体过程是这样的:

    1. 启动时,指定好 connection string,连接超时时间,序列化工具等。
    2. 创建并启动 eventThread,用于接收事件,并调度事件监听器 Listener 的执行。
    3. 连接到 zookeeper 服务器,同时将 ZKClient 自身作为默认的 Watcher。
  • 为节点注册Watcher:

    ZooKeeper 的三个方法:getData、getChildren、exists.

    ZKClient 都提供了相应的代理方法。就拿 exists 来看:

    可以看到,是否注册 watcher,由 hasListeners(path)来决定的。

    hasListeners 就是看有没有与该数据节点绑定的 listener。

    所以,默认情况下,都会自动的为指定的 path 注册 watcher,并且是默认的 watcher (ZKClient)。怎么才能让 hasListeners 判定值为 true 呢,也就是怎么才能为 path 绑定 Listener 呢?

  • ZKClient提供了订阅功能:

    一个新建的会话,只需要在取得响应的数据节点后,调用 subscribteXxx 就可以订阅上相应的事件了。

4)客户端处理变更(Watcher通知)

前面已经知道,ZKClient 是默认的 Watcher,并且在为各个数据节点注册的 Watcher 都是这个默认的 Watcher。那么该是如何将各种事件通知给相应的 Listener 呢?

处理过程大致可以概括为下面的步骤:

  1. 判断变更类型:变更类型分为 State 变更、ChildNode 变更(创建子节点、删除子节点、修改子节点数据)、NodeData 变更(创建指定 node,删除节点,节点数据变更)。
  2. 取出与 path 关联的 Listeners,并为每一个 Listener 创建一个 ZKEvent,将 ZkEvent 交给 ZkEventThread 处理。
  3. ZkEventThread 线程,拿到 ZkEvent 后,只需要调用 ZkEvent 的 run 方法进行处理。 从这里也可以知道,具体的怎么如何调用 Listener,还要依赖于 ZkEvent 的 run()实现了。

注册监听 watcher:

接口类 注册监听方法 解除监听方法
IZkChildListener(子节点) ZkClient的subscribeChildChanges方法 ZkClient 的unsubscribeChildChanges 方法
IZkDataListener(数据) ZkClient 的subscribeDataChanges 方法 ZkClient 的 unsubscribeDataChanges 方法
IZkStateListener(客户端状 态) ZkClient 的 subscribeStateChanges 方 法 ZkClient 的 unsubscribeStateChanges 方法

在 ZkClient 中客户端可以通过注册相关的事件监听来实现对 Zookeeper 服务端时间的订阅。

其中 ZkClient 提供的监听事件接口有以下几种:

其中 ZkClient 还提供了一个 unsubscribeAll 方法,来解除所有监听。

Zookeeper 中提供的变更操作有:节点的创建、删除,节点数据的修改:

  1. 创建操作,数据节点分为四种,ZKClient 分别为他们提供了相应的代理:

  2. 删除节点的操作:

  3. 修改节点数据的操作:

  • writeDataReturnStat():写数据并返回数据的状态。
  • updateDataSerialized():修改已序列化的数据。执行过程是:先读取数据,然后使用DataUpdater 对数据修改,最后调用 writeData 将修改后的数据发送给服务端。

5)序列化处理

ZooKeeper 中,会涉及到序列化、反序列化的操作有两种:getData、setData。在 ZKClient 中,分别用 readData、writeData 来替代了。

对于 readData:先调用 zookeeper 的 getData,然后进行使用 ZKSerializer 进行反序列化工 作。

对于 writeData:先使用 ZKSerializer 将对象序列化后,再调用 zookeeper 的 setData。

6)ZkClient如何解决使用ZooKeeper客户端遇到的问题的呢?

  • Watcher 自动重注册:这个要是依赖于 hasListeners()的判断,来决定是否再次注册。如果对此有不清晰的,可以看上面的流程处理的说明。
  • Session 失效重连:如果发现会话过期,就先关闭已有连接,再重新建立连接。
  • 异常处理:对比 ZooKeeper 和 ZKClient,就可以发现 ZooKeeper 的所有操作都是抛异常 的,而 ZKClient 的所有操作,都不会抛异常的。在发生异常时,它或做日志,或返回空, 或做相应的 Listener 调用。

相比于 ZooKeeper 官方客户端,使用 ZKClient 时,只需要关注实际的 Listener 实现即可。所 以这个客户端,还是推荐大家使用的。

posted @ 2020-02-20 08:22  林老头儿  阅读(1127)  评论(0编辑  收藏  举报