天天看點

(十一)、ZNode Watches(事件)ZooKeeper對Node的增、删、改、查都可以觸發監聽Zookeeper如何正确設定和擷取watcher

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的工作流程。

(十一)、ZNode Watches(事件)ZooKeeper對Node的增、删、改、查都可以觸發監聽Zookeeper如何正确設定和擷取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也會丢失,需要自己編碼做一些額外的處理