(十一)、ZNode Watches(事件)

ZooKeeper对Node的增、删、改、查都可以触发监听

Watch事件是一次性触发器,当Watch监视的数据发生变化时,通知设置了该Watch的Client,即watcher(观察者),Watch事件是异步发送至观察者。

Watch是一次性触发的并且在获取Watch事件和设置新Watch事件之间有延迟,所以不能可靠的观察每个节点的每一次变化。客户端监视一个节点,总是先获取Watch事件,在发现节点的数据变化,Watch事件的顺序对应于ZooKeeper服务所见的数据更新的顺序。

Zookeeper如何正确设置和获取watcher

Watcher 设置是开发中最常见的,需要搞清楚watcher的一些基本特征,对于exists、getdata、getchild对于节点的不同操作会收到不同的 watcher信息。
Watcher是Zookeeper用来实现distribute lock, distribute configure, distribute queue等应用的主要手段。要监控data_tree上的任何节点的变化(节点本身的增加,删除,数据修改,以及孩子的变化)都可以在获取该数据时注册一个Watcher,这有很像Listener模式。一旦该节点数据变化,Follower会发送一个notification response,client收到notification响应,则会查找对应的Watcher并回调他们。 有以下接口可以注册Watcher:
  • Stat exists(final String path, Watcher watcher)
  • Stat exists(String path, boolean watch)
  • void exists(String path, boolean watch, StatCallback cb, Object ctx)
  • void exists(final String path, Watcher watcher, StatCallback cb, Object ctx)
  • byte[] getData(final String path, Watcher watcher, Stat stat)
  • byte[] getData(String path, boolean watch, Stat stat)
  • void getData(final String path, Watcher watcher, DataCallback cb, Object ctx)
  • void getData(String path, boolean watch, DataCallback cb, Object ctx)
  • List<string> getChildren(final String path, Watcher watcher)
  • List<string> getChildren(String path, boolean watch)
  • void getChildren(final String path, Watcher watcher,ChildrenCallback cb, Object ctx)
操作 方法 触发watcher watcher state watcher type watcher path
Create当前节点 getdata × × × ×
getchildren 3 4
exists × × × ×
set当前节点 getdata 3 3
getchildren × × × ×
exists 3 3
delete当前节点 getdata 3 2
getchildren 3 2
exists 3 2
create子节点 getdata × × × ×
getchildren 3 4
exists × × × ×
set子节点 getdata × × × ×
getchildren × × × ×
exists × × × ×
delete子节点 getdata × × × ×
getchildren 3 4
exists × × × ×
恢复连接 getdata 1 -1 ×
getchildren 1 -1 ×
exists 1 -1 ×
恢复连接session未超时 getdata -112 -1 ×
getchildren -112 -1 ×
exists -112 -1 ×
恢复连接session超时 getdata 3 -1 ×
getchildren 3 -1 ×
exists 3 -1 × 
注: state = 2 表示删除事件;state = 3表示节点数据变更;state =4表示子节点事件;state = -1表示session事件。 type = -112表示session失效;type = 1表示session建立中;tpye = = 3表示session建立成功。×表示否,√表示是。
如果参数需要传递watcher,则可以自己定义Watcher进行回调处理。如果是Boolean型变量,当为true时,则使用系统默认的Watcher,系统默认的Watcher是在zookeeper的构造函数中传递的Watcher。如果Watcher为空或者Boolean变量时为false,则表明不注册Watcher。如果获取数据后不需要关注该数据是否变化,就不需要注册Watcher。上面没有返回值的都是异步调用模式。需要注意的是,一旦Watcher被调用后,将会从map中删除,如果还需要关注数据的变化,需要再次注册。 Watcher原理 要搞清楚Watcher的原理,让我们看看Watcher的工作流程。

  • exists方法: 设置watcher时,如果对应服务端已经不存在node时,watcher是不会留在服务端,下次不会被触发。针对这种情况需要判断返回的stat == null来进行处理
  • getChildren方法: 和exist一样,需要处理节点不存在时watcher不会被记录。 还有一个点,当前的父node发生delete变化时,也可以得到触发
  • getData方法: 和exist一样,需要处理节点不存在时watcher不会被记录

要了解watcher是否会丢失,必须要清楚zookeeper整套watcher机制的实现:

  • Watcher是一个本地jvm的callback,在和服务端交互过程中是不会进行传递的。只是会将是否有watcher的boolean变量传递给server端
  • 在服务端,在FinalRequestProcessor处理对应的node操作时,会根据客户端传递的watcher变量,添加到对应的zkDataBase中进行持久化存储,同时将自己NIOServerCnxn做为一个Watcher callback,监听服务端事件变化
  • leader通过投票通过了某次node变化请求后,通知给对应的follower,follower根据自己内存中的zkDataBase信息,发送notification信息给zookeeper 客户端
  •  zookeeper客户端接收到notification信息后,找到对应变化path的watcher列表,挨个进行触发回调。

可能存在的问题:

1. client向连接的server提交了watcher事件后,对应的server还未来得及提交给leader就直接出现了jvm crash,这时对应的watcher事件会丢失。(理论上正常关闭zookeeper server,不会存在该问题,需要客户端进行重试处理)
2. client在发生一次failover时,可以自动对新的server的notification使用watcher set,可以通过设置jvm变量:zookeeper.disableAutoWatchReset进行,默认为false。如果为true,则不进行自动使用的行为)
3. client出现session expired时,需要重新创建一个zookeeper client实例,此时对应的watcher set也会丢失,需要自己编码做一些额外的处理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章