ZK Watcher 的原理和实现
什么是 ZK Watcher
基于 ZK 的应用程序的一个常见需求是需要知道 ZK 集合的状态。为了达到这个目的,一种方法是 ZK 客户端定时轮询 ZK 集合,检查系统状态是否发生了变化。然而,轮询并不是一种高效的方式,尤其是在状态变化的发生频率很低的时候
因此,ZK 提供了一种通过通知客户端感兴趣的具体时间来避免轮询造成的性能问题的方式,即设置 Watcher 的方式。通过设置 Watcher,ZK 客户端可以对指定的 znode 注册一个通知请求,在 znode 发生变化时收到一个单次的通知。例如,在 znode 被删除时向 Watcher 发送节点被删除的通知
应用 ZK Watcher 的代码通常遵循如下的框架
zk.exists("myZnode", myWatcher, existsCallback, null); Watcher myWatcher new Watcher() { public void process(WatchedEvent event) { // process the watch event } } StatCallback existsCallback = new StatCallback() { public void processResult(int rc, String path, Object ctx, Stat stat) { // process the result of the exists call } }
上面的代码框架中以 exists 操作为例,展示了异步调用 ZK 操作并注册 Watcher 的一般用法
WatchedEvent 的分类
Watcher 的使用一个重要的内容就是了解 Watcher 如何设置以及何时触发,并不是所有的 ZK 操作都可以设置 Watcher,Watcher 也不是会被所有事件触发
抛开被重载的连接状态的 WatchedEvent,业务过程中会遇到的 WatchedEvent 分为以下几种
- NodeCreated - 可以通过 exists 调用设置 Watcher,在 znode 从无到有创建的时候被触发
- NodeDeleted - 可以通过 exists 或者 getData 调用设置 Watcher,在 znode 被删除时触发
- NodeDataChanged - 可以通过 exists 或者 getData 调用设置 Watcher,在 znode 数据发生变化时触发
- NodeChildrenChanged - 可以通过 getChildren 调用设置 Watcher,在 znode 的直接子节点创建或删除时触发
- DataWatchRemoved - 在 exists 或者 getData 设置的 Watcher 被删除时触发对应的 Watcher
- ChildWatchRemoved - 在 getChildren 设置的 Watcher 被删除时触发对应的 Watcher
可以看到,只有 exists 和 getData 和 getChildren 三种操作能够设置 Watcher
注意,getData 创建的 Watcher 不会接收到 NodeCreated 事件,这是因为 getData 在节点不存在的时候会抛出 KeeperException.NoNodeException 异常,而不会设置 Watcher。