zookeeper的watcher机制
ZooKeeper 提供了分布式数据发布/订阅功能,一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使他们能够做出相应的处理。
ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些事件触发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
触发事件种类很多,如:节点创建,节点删除,节点改变,子节点改变等。
总的来说可以概括 Watcher 为以下三个过程:客户端向服务端注册 Watcher、服务端事件发生触发 Watcher、客户端回调 Watcher 得到触发事件情况。
Watch 机制特点
- 一次性触发
事件发生触发监听,一个 watcher event 就会被发送到设置监听的客户端,这种效果是一次性的,后续再次发生同样的事件,不会再次触发。 - 事件封装
ZooKeeper 使用 WatchedEvent 对象来封装服务端事件并传递。
WatchedEvent 包含了每一个事件的三个基本属性:通知状态(keeperState),事件类型(EventType)和节点路径(path) - event 异步发送
watcher 的通知事件从服务端发送到客户端是异步的。 - 先注册再触发
Zookeeper 中的 watch 机制,必须客户端先去服务端注册监听,这样事件发送才会触发监听,通知给客户端。
常见的zookeeper服务的操作
操作 | 描述 |
---|---|
create | 创建一个znode(必须要有父节点) |
delete | 删除一个znode(该znode不能有任何子节点) |
exists | 测试一个znode是否存在并且查询他的元数据 |
getACL,setACL | 获取/设置一个znode的ACL |
getChildren | 获取一个znode的子节点列表 |
getData,setdata | 获取/设置一个znode所保存的数据 |
sync | 将客户端的znode视图与zookeeper同步 (将当前客户端连接上的znode数据与主节点同步,将数据更新到最新) |
注意:
- 在使用delete 或 setData操作时必须提供被更新的版本号(可以通过exists操作获得)。
- zookeeper的写操作是具有原子性的,在写操作没有完成前,zookeeper允许客户端读到的数据之后于zookeeper服务的最新状态。
- zookeeper中有一个被称为
multi
的操作,用于将多个基本操作集合组成一个操作单元,并确保这些基本操作同时被成功执行,或者同时失败。
常见的通知状态和事件类型
同一个事件类型在不同的通知状态中代表的含义有所不同,下表列举了常见的通知状态和事件类型。
虽然说zookeeper需要先注册再触发,但是连接状态事件(type=None, path=null)不需要客户端注册,客户端只要有需要直接处理就行了。
不同的观察能被触发事件不同
- 当所观察的znode被创建、删除或其数据被更新时,设置在exists 操作上的观察将被触发。
- 当所观察的znode 被删除,或其数据被更新时,设置在getData操作上的观察将被触发。创建znode不会触发getData操作上的观察,应为getData操作成功执行的前提时znode必须已经存在
- 所观察的znode的一个子节点被创建或被删除的时候,或者所观察的znode自己被删除的时候,设置在getChildren操作上的观察将被触发,可以通过观察事件的类型来判断被删除的是 znode 还是其子节点;NodeDelete类型代表znode被删除,NodeChildrenChanged类型代表一个子节点被删除。
KeeperState | EventType | 触发条件 | 说明 |
---|---|---|---|
None(-1) | 客户端与服务端成功建立连接 | ||
SyncConnected(0) | NodeCreated(1) | Watcher 监听的对应数据节点被创建 | |
NodeDeleted(2) | Watcher 监听的对应数据节点被删除 | 此时客户端和服务器处于连接状态 | |
NodeDataChanged(3) | Watcher 监听的对应数据节点的数据内容发生变更 | ||
NodeChildChanged(4) | Wather 监听的对应数据节点的子节点列表发生变更 | ||
Disconnected(0) | None(-1) | 客户端与 ZooKeeper 服务器断开连接 | 此时客户端和服务器处于断开连接状态 |
Expired(-112) | Node(-1) | 会话超时 | 此时客户端会话失效,通常同时也会受到SessionExpiredException 异常 |
AuthFailed(4) | None(-1) | 通常有两种情况,1:使用错误的schema 进行权限检查 2:SASL 权限检查失败 | 通常同时也会收到 AuthFailedException 异常 |
Shell 客户端设置 watcher
在zookeeper中,不是所有的命令后面都可以添加监听的,我们可以在zookeeper的shell客户端下使用 help 命令查看所有的命令,命令后面有 [watch] 的则表示可以设置监听。
我们在根路径下创建一个持久节点来测试这个监听,这里测试的是当该节点里的数据变化时触发。
- 创建测试的持久节点
- 设置数据变化的监听
- 使用另一个客户端来修改数据,触发这个监听。