Zookeeper:分布式事件监听
关于
实现对ZooKeeper服务器端的事件监听,是客户端操作服务器的一项重点工作。在 Curator 的API中,事件监听有两种模式:
- 一种是标准的观察者模式:通过Watcher监听器实现的;
- 另一种是缓存监听模式:通过引入了一种“本地缓存视图”Cache机制去实现的。
- 可以理解为一个本地缓存视图与远程ZooKeeper视图的对比过程,简单来说,Cache在客户端缓存了ZNode的各种状态,当感知到Zk集群的ZNode状态变化时,会触发事件,注册的监听器会处理这些事件。
- 虽然,Cache是一种缓存机制,但是可以借助Cache实现实际的监听。
二者的最大的不同在于:
- Cache机制提供了反复注册的能力,而观察模式的Watcher监听器只能监听一次。
- 在类型上,Watcher监听器比较简单,只有一种。Cache事件监听的种类有3种:Path Cache,Node Cache 和 Tree Cache。
Watcher监听器
在 ZooKeeper 中,Watcher 监听器的使用过程:
- 定义一个 Watcher 接口的实例:使用 Watcher 接口的事件回调方法:“process(WatchedEvent event)”定义回调处理逻辑。如下:
//演示:定义一个监听器 Watcher w = new Watcher() { @Override public void process(WatchedEventwatchedEvent) { log.info("监听器watchedEvent:" + watchedEvent); } };
- 通过“实现了Watchable<T>接口”的构造者的“usingWatcher(Watcher w)”方法,为构造者设置 Watcher 监听器实例。如下:
//为GetDataBuilder实例设置监听器 byte[] content = client.getData().usingWatcher(w).forPath(workerPath);
- 可以分别通过 getData()、exists()、getChildren() 方法去设置监听器。
一个 Watcher 监听器在向服务器端完成注册后,当服务器端的一些事件触发了这个 Watcher,就会向注册过的客户端会话发送一个事件通知来实现分布式的通知功能。
- 在 Curator 客户端收到服务器端的通知后,会封装一个通知事件“WatchedEvent”的实例,再传递给监听器的“process(WatchedEvent e)”回调方法。
示例:
关于“Watcher”、“Watchable<T>”、“WatchedEvent”、“WatcherEvent”
Watcher接口:用于表示一个标准的事件处理器,用来定义收到事件通知后相关的回调处理逻辑。
- 接口中包含两个内部枚举类:“KeeperState”(“通知状态”)和“EventType”(“事件类型”)。
Watchable<T>接口:定义了 usingWatcher(Watcher w) 用于为实现了此接口的构造者设置监视器。
- 实现了 Watchable<T> 接口的构造者,如:GetDataBuilder、GetChildrenBuilder 和 ExistsBuilder。(分别对应了前一节所述三个方法)
- 在 Curator 中,Watchable<T> 接口的源代码如下:
package org.apache.curator.framework.api; import org.apache.ZooKeeper.Watcher; public interface Watchable<T> { T watched(); T usingWatcher(Watcher w); T usingWatcher(CuratorWatcher cw); }
WatchedEvent通知事件:Curator 客户端将服务器端的通知(WatcherEvent)封装为一个“WatchedEvent”实例,再传递给监听器的“process(WatchedEvent e)”回调方法。
- WatchedEvent包含了三个基本属性:
- 通知状态(keeperState)
- 事件类型(EventType)
- 节点路径(path)
- WatchedEvent 中所用到的通知状态和事件类型定义在 Watcher 接口中。(如上图)
- 关于“WatchedEvent”与“WatcherEvent”:
WatcherEvent:从 ZooKeeper 服务器端直接通过网络传输传递过来的通知事件实例的类型; WatchedEvent:Curator 将服务器端的通知事件封装后的事件实例的类型;【WatchedEvent 类型没有实现序列化接口 java.io.Serializable,因此不能用于网络传输】 WatcherEvent 传输实例 和 Curator的 WatchedEvent 封装实例,在名称上基本上一样,只有一个字母之差,而且功能也是一样的,都表示的是同一个服务器端事件。