watcher的特征
zookeeper的一大特點之一就是watch機制,所有基于zookeeper的消息通知機制基本上都是建議在watcher機制之上的,比如業界比較有名的由360公司開源的Qconf的底層就是基于這個實作的,本章其實就是想将zookeeper的watcher的資料存儲、watcher的添加、watcher的觸發整個過程講解清楚,友善大家有個清晰的認識。

watch特性
watcher的存儲
說明:
watcher主要分為dataWatches和childWatches,其中dataWatches是儲存節點層面的watcher對象的,childWatches是儲存子節點層面的watcher對象的。核心的點在于
WatchManager資料結構。
watcher的儲存結構
WatchManager内部主要維持了
watchTable(path->watcher)以及
watch2Paths(watcher->path)兩個映射關系,其實這也就是代表了一個path有多個watcher,或一個watcher同時watch了多個path的場景。
整個watcher的添加過程其實同時需要修改watchTable和watch2Paths兩個map對象,具體的修改操作可以參考上面的代碼貼圖。
watcher的添加
zookeeper的watcher的添加一般通過三個途徑,分别是通過
exists、
getData getChildren三種方式添加,其中exists用于判斷節點是否存在,getData擷取節點資料,getChildren擷取子節點。其實從這個地方我們可以看出來其實watcher的添加其實是附加動作,基本上都是在主動作的同時添加一下watcher。
從下面的API我們其實就看出來了,對應上面提到的3個動作提供3個接口用于添加watcher動作。
watcher的添加方式
exists添加watcher
exists的watcher
直覺的感受就是我們在執行exists的api的時候,我們最終通過statNode的接口儲存了watcher,
注意這裡儲存在dataWatches當中。
getData添加watcher
getData的watcher
直覺的感受就是我們再執行getData的時候,我們最終通過addWatch的接口儲存了watcher,
getChildren添加watcher
getChildren的watcher
注意這裡的儲存在childWatches當中watcher添加過程
資料流入口
其實資料是在FinalRequestProcessor當中進行寫入的,根據OpCode執行的寫入操作,是以基本上我認為通過這個圖基本上能夠了解到watcher寫入的入口了。
watcher的觸發
watcher觸發後動作
從這裡我們可以看出來并且印證一個觀點,那就是watcher是一次性觸發的,原因就在于每次我們triggerWatch的時候我們都會把watcher從watchTable當中移除,根據具體觸發的path路徑找到對應的watcher,然後移除watcher并觸發watcher的後續動作。注意這裡觸發了watcher。
觸發watcher的動作
從這裡我們可以看出來,觸發watcher的幾個動作主要包括建立節點(createNode)、删除節點(deleteNode)、資料變更(setData)。
同時觸發dataWatches和childWatches
從上圖可以看出來我們在建立節點的時候會同時判斷是否觸發dataWatches和childWatches,這也就解釋了childWatches是如何被觸發的。