1.1 监听器原理 

  1. 首先要有一个main()线程
  2. 在main()线程中创建Zookeeper客户端,这时就会创建两个线程connect线程负责网络连接通信,listen线程负责监听
  3. 通过connect线程将注册的监听事件发送给Zookeeper服务器
  4. 在Zookeeper的注册监听列表中将注册的监听事件添加到列表中,表示这个服务器中的/path,即根目录这个路径被客户端监听了
  5. 一旦被监听的服务器根目录下,数据或路径发生改变,Zookeeper服务器就会将这个消息发送给Listener线程
  6. Listener线程内部调用process方法,采取相应的措施

图1 监听器原理

1.2 Watcher监听

        客户端首先将 Watcher注册到服务端,同时将 Watcher对象保存到客户端的watch管理器中。当Zookeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的 Watch管理器会触发相关 Watcher事件来回调相应处理逻辑,从而完成整体的数据 发布/订阅流程。


        Watcher实现由三个部分组成,分别是Zookeeper服务端、Zookeeper客户端以及客户端的ZKWatchManager对象,客户端首先将 Watcher注册到服务端,同时将 Watcher对象保存到客户端的watch管理器中。当Zookeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的 Watch管理器会触发相关 Watcher来回调相应处理逻辑,从而完成整体的数据发布/订阅流程。

图8 Watcher架构

        其中,客户端并没有把 watcher 实例传给服务端,而只是设置一个标识位告诉它要监听某个节点的变化。同理,服务端节点发生变化的时候,只能简单“通知” 客户端变化的事件,而具体发生了什么变化,则需要客户端自己去服务端再次获取。

        Watcher接口定义了事件的回调方法:process(WatchedEvent event)。一个Watcher监听器在向服务端完成注册后,当服务端的一些事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知(WatcherEvent),来实现分布式的通知功能。客户收到服务器的通知后,Curator 会封装一个WatchedEvent 事件实例,传递给监听器的回调方法process(WatchedEvent event)WatchedEvent包含了三个基本属性:通知状态(keeperState)、事件类型(EventType)以及节点路径(path)。

表1 通知状态以及事件类型

KeeperState

EventType

触发条件

说明

SyncConnected

None

客户端与服务端成功建立连接

客户端和服务器处于连接状态

NodeCreated

Watcher监听的对应数据节点被创建

NodeDeleted

Watcher监听的对应数据节点被删除

NodeDataChanged

Watcher监听的对应数据节点的数据内容发生变更

NodeChildChanged

Wather监听的对应数据节点的子节点列表发生变更

Disconnected

None

客户端与ZooKeeper服务器断开连接

客户端与服务器断开连接时

Expired

None

会话超时

会话session失效时

AuthFailed

None

通常有两种情况,1:使用错误的schema进行权限检查 2:SASL权限检查失败

身份认证失败时

        Watcher监听器是一次性的。利用Watcher来对节点进行监听操作,当事件被触发之后,所对应的 watcher 会被立马删除,如果要反复使用,就需要反复的使用usingWatcher提前注册。所以,Watcher监听器不能应用于节点的数据变动或者节点变动这样的一般业务场景。而是适用于一些特殊的,比如会话超时、授权失败等这样的特殊场景。

1.3 Cache事件监听

      

        既然Watcher监听器是一次性的,在开发过程中需要反复注册Watcher,比较繁琐。Curator引入了Cache来监听ZooKeeper服务端的事件。Cache事件监听可以理解为一个本地缓存视图与远程Zookeeper视图的对比过程,简单来说,Cache在客户端缓存了znode的各种状态,当感知到zk集群的znode状态变化,会触发event事件,注册的监听器会处理这些事件。Cache对ZooKeeper事件监听进行了封装,能够自动处理反复注册监听,主要有以下三类:

表2 Cache封装事件监听类

类名

用途

NodeCache

监听节点对应增、删、改操作

PathChildrenCache

监听节点下一级子节点的增、删、改操作

TreeCache

可以将指定的路径节点作为根节点,对其所有的子节点操作进行监听,呈现树形目录的监听

       NodeCache使用的第一步,就是构造一个NodeCache缓存实例,有两个构造方法NodeCache(CuratorFramework client, String path) 和NodeCache(CuratorFramework client, String path, boolean dataIsCompressed) 第一个参数就是传入创建的Curator的框架客户端,第二个参数就是监听节点的路径,第三个重载参数dataIsCompressed 表示是否对数据进行压缩。

        NodeCache使用的第二步,就是构造一个NodeCacheListener监听器实例,NodeCacheListener监听器接口,只定义了一个简单的方法 nodeChanged,当节点变化时,这个方法就会被回调。

        再创建完NodeCacheListener的实例之后,需要将这个实例注册到NodeCache缓存实例,使用缓存实例的addListener方法,然后使用缓存实例nodeCache的start方法,启动节点的事件监听。

图9 NodeCache节点缓存监听

        PathChildrenCache 子节点监听,只能监听子节点,监听不到当前节点,不能递归监听,子节点下的子节点不能递归监控。Tree Cache节点树缓存可以看做是上两种的合体,Tree Cache观察的是当前ZNode节点的所有数据。而TreeCache节点树缓存是PathChildrenCache的增强,不光能监听子节点,也能监听节点自身,使用步骤和NodeCache类似。

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐