(十一)、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也會丟失,需要自己編碼做一些額外的處理

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