先談談watcher和watcheEvent
剛學zookeeper的時候,都會被坑一次,以為watcher的監(jiān)聽是永久的。其實不然,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發(fā)送事件。

Paste_Image.png
何時會產生type=None的事件呢?狀態(tài)轉變的時候!

Paste_Image.png
初始化的sessionState=Disconnected,
所以第一次ping成功,(zookeeper client會不斷的給server發(fā)送ping指令)
會產生一個watchEvent:State=SyncConnected,type=None,
此時sessionState=SyncConnected,所以后續(xù)的ping就不會產生事件了。
當zk監(jiān)聽watcher的時候,如果發(fā)生網絡斷鏈,且在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 無視,因為連不上你做啥事都沒用,也就改改某些狀態(tài),能連上的話要么收到SyncConneted事件,要么收到Expired 事件
- Expired重新構建zookeeper客戶端。
- SyncConnected
- 對于type!=None重新注冊watcher.
- 對于監(jiān)聽的type做后續(xù)處理
再談談zookeeper客戶端操作的Code
- 同步操作會收到KeeperException
- 異步操作會收到rc
對于KeeperException 可以使用code()得到Code,對于rc,可以使用KeeperException.Code.get(rc)得到Code
Code表示你這次操作的結果
例如對于delete(path,version)
- 如果節(jié)點存在那么會收到ok
- 如果節(jié)點不存在那么會收到NoNode
那么如果是斷連呢?
- 如果正處于斷連,那么會產生ConnectionLoss。
- 如果sessionExpired或者zookeeper.close那么會收到sessionExpired
所以對于rc處理方式是:
- ConnectionLoss,局部重試
- sessionExpired,重建zookeeper客戶端
- 其他,業(yè)務邏輯處理。
對于zookeeper的初略理解,有問題可以指點指點。
另外關于測試。
模擬zookeeper的sessionExpired可以看看curator的KillSession