在实际中我们客户端希望能够时时感知到数据的变化,这时候ZK的watch机制就起了很重要的作用。
一、ZooKeeper 的watch机制
ZooKeeper支持 Watch,客户端可以在znode上设置 Watch。
znode更改时,将触发并删除监视。触发监视后,客户端会收到一个数据包,说明znode已更改。
3.6.0中的新增功能:
客户端还可以在znode上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发注册znode以及所有子znode的更改。
支持 Watch的 客户端命令:
- stat path [watch]
- ls path [watch]
- ls2 path [watch]
- get path [watch]
新版本的方式:
- stat -w path
- ls -w path
- ls2 -w path
- get -w path
二、ZooKeeper 的watch栗子
使用命令get -w <path>进行监听:
如果使用get /test/test1 watch,也能够监听,但是会有一个警告:
此时使用另外一个客户端去更改 /test/test1 节点的数据,我们就可以看到原来的客户端自动收到了一个WATCHER 通知。
如果我们在进行set操作,并没有再次受到通知,这个就是ZK的一个监听机制决定的:znode更改时,将触发并删除监视,也就是说只能监听一次。
如果我们监听的是节点/test,但是我们修改的是/test/test1的节点的话,这个是监听不到的。
在3.6.x版本中支持:在znode上设置永久性的递归监视,这些监视在触发时不会删除,并且会以递归方式触发注册znode以及所有子znode的更改。那么这个怎么呢?
先看下我们当前的ZK版本是否满足3.6.x:
满足的情况下,那么要怎么操作呐?使用help看下说明:
使用方式:addWatch [-m mode] path
可选模式是[PERSISTENT,PERSISTENT_RECURSIVE]之一-默认为PERSISTENT_RECURSIVE。
PERSISTENT:只有当前监听的节点有变化了,才能收到通知,会持续的收到每次的通知。
PERSISTENT_RECURSIVE:当前节点和子节点有变化了,就会收到通知,会持续的收到每次的通知。
三、watch监听的事件类型和状态类型
事件类型:(znode节点相关的):
EventType.NodeCreated
EventType.NodeDataChanged
EventType.NodeChildrenChanged
EventType.NodeDeleted
状态类型:(是跟客户端实例相关的):
KeeperState.Disconnected
KeeperState.SyncConnected
KeeperState.AuthFailed
KeeperState.Expired
四、watch特性
wather的特性:一次性,客户端串行执行,轻量。
一次性(3.6.x支持永久递归监视):对于ZK的watcher,你只需要记住一点:zookeeper有watch事件,是一次性触发的,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher,由于zookeeper的监控都是一次性的,所以每次都必须监控。
客户端串行执行:客户端watcher回调的过程是一个串行同步的过程,这为我们保证了顺序,同时需要开发人员注意一点,千万不用因为一个watcher的处理逻辑影响了整个客户端的watcher回调。
轻量:WatcherEvent是ZooKeeper整个Watcher通知机制的最小通知单元。整个单元结构只包含三部分:通知状态,事件类型和节点路径。也就是说Watcher通知非常的简单,只会告诉客户端发生了事件而不会告知其具体内容,需要客户自己去进行获取,而不会直接提供具体的数据内容。