先谈谈watcher和watcheEvent
刚学zookeeper的时候,都会被坑一次,以为watcher的监听是永久的。其实不然,watcher在大多数时候都只调用一次。
zookeeper使用HashMap<Path,Watcher>维护了所有路径的watcher,
private static class ZKWatchManager implements ClientWatchManager {
private final Map<String, Set<Watcher>> dataWatches = new HashMap<String, Set<Watcher>>();
private final Map<String, Set<Watcher>> existWatches = new HashMap<String, Set<Watcher>>();
private final Map<String, Set<Watcher>> childWatches = new HashMap<String, Set<Watcher>>();
所有不论注册多少次,都只会有一个watcher存在。当watcheEvent产生的时候,会移除对应path的watcher,并且回调。
然而,当type=None的时候,就不会移除watcher,会向所有watcher发送事件。
何时会产生type=None的事件呢?状态转变的时候!
初始化的sessionState=Disconnected,
所以第一次ping成功,(zookeeper client会不断的给server发送ping指令)
会产生一个watchEvent:State=SyncConnected,type=None,
此时sessionState=SyncConnected,所以后续的ping就不会产生事件了。
当zk监听watcher的时候,如果发生网络断链,且在sessionTimeout/2的时间内都没有恢复连接。
那么所有注册的watcher都会接收到
state=Disconnected,type=None,path=Null的watchEvent
此时sessionState=Disconnected..
- 如果在剩下sessionTimeout/2的时间内恢复连接,即ping通了
那么就会收到watchEvent:state=SyncConnected,type=None,path=Null - 如果超过sessionTimeout时间恢复连接,那么就会收到
watchEvent:state=Expired,type=None,path=Null
此时表示zookeeper客户端真正与服务端失去连接,就需要重建zookeeper的客户端了。 - 如果超过sessionTimeout时间也没恢复连接,只有等恢复连接才会收到Expired事件。
所以对于watcheEvent的事件的处理方式是:
- DisConneted 无视,因为连不上你做啥事都没用,也就改改某些状态,能连上的话要么收到SyncConneted事件,要么收到Expired 事件
- Expired重新构建zookeeper客户端。
- SyncConnected
- 对于type!=None重新注册watcher.
- 对于监听的type做后续处理
再谈谈zookeeper客户端操作的Code
- 同步操作会收到KeeperException
- 异步操作会收到rc
对于KeeperException 可以使用code()得到Code,对于rc,可以使用KeeperException.Code.get(rc)得到Code
Code表示你这次操作的结果
例如对于delete(path,version)
- 如果节点存在那么会收到ok
- 如果节点不存在那么会收到NoNode
那么如果是断连呢?
- 如果正处于断连,那么会产生ConnectionLoss。
- 如果sessionExpired或者zookeeper.close那么会收到sessionExpired
所以对于rc处理方式是:
- ConnectionLoss,局部重试
- sessionExpired,重建zookeeper客户端
- 其他,业务逻辑处理。
对于zookeeper的初略理解,有问题可以指点指点。
另外关于测试。
模拟zookeeper的sessionExpired可以看看curator的KillSession