Zookeeper之Watch機(jī)制源碼分析

Zookeeper的Watch機(jī)制提供了服務(wù)通知功能,包含客戶端的注冊(cè)和觸發(fā)、服務(wù)端的注冊(cè)和觸發(fā)


image.png
Zookeeper客戶端:

通過(guò)ZKWatchManager管理
結(jié)構(gòu)都是存儲(chǔ)Map<String, Set<Watcher>>
例如:{"/abc",Set<Watcher>} 表示/abc節(jié)點(diǎn)下綁定了Watcher有哪些
1、臨時(shí)的一次性的,用完即刪除有dataWatches、existWatches、childWatches
2、永久性的有persistentWatches、persistentRecursiveWatches(表示遞歸的永久性Watcher)

Zookeeper服務(wù)端:

有dataWatches和childWatches
每個(gè)屬性下面都有watchTable、watch2Paths。
服務(wù)端的Watcher表示當(dāng)前客戶端的實(shí)現(xiàn)類NioServerCnxn
watchTable:Map<String, Set<Watcher>>
例如:{"/abc",Set<Watcher>} 表示/abc節(jié)點(diǎn)下有哪些客戶端含有Watcher
watch2Paths: Map<Watcher, Set<String>>
例如:{Watcher,Set<String>} 表示當(dāng)前客戶端下有那些路徑下有Watcher

客戶端注冊(cè)

當(dāng)調(diào)用自定義getData方法時(shí)


image.png

1、getData
這里并沒(méi)有注冊(cè)
org.apache.zookeeper.ZooKeeper#getData


image.png

①、把watcher和clientPath封裝成DataWatchRegistration對(duì)象
org.apache.zookeeper.ZooKeeper.DataWatchRegistration#DataWatchRegistration
image.png

org.apache.zookeeper.ZooKeeper.WatchRegistration#WatchRegistration


image.png

②、提交請(qǐng)求submitRequest
把封裝的對(duì)象使用cnxn.submitRequest方法提交請(qǐng)求,最終把DataWatchRegistration wcb賦值給數(shù)據(jù)包Packet的watchRegistration屬性
image.png

2、通過(guò)SendThread線程的readResponse讀取響應(yīng)數(shù)據(jù)
①、readResponse
org.apache.zookeeper.ClientCnxn.SendThread#readResponse
image.png

②、finishPacket
org.apache.zookeeper.ClientCnxn#finishPacket
image.png

③、register
通過(guò)數(shù)據(jù)包的WatchRegistration屬性值注冊(cè)watch
org.apache.zookeeper.ZooKeeper.WatchRegistration#register


image.png

org.apache.zookeeper.ZooKeeper.DataWatchRegistration#getWatches
獲取的是ZKWatchManager#dataWatches屬性
image.png

最終把當(dāng)前watch注冊(cè)給了ZKWatchManager的dataWatches屬性值。

服務(wù)端注冊(cè)

服務(wù)端的注冊(cè)是在請(qǐng)求處理鏈的最后一個(gè)請(qǐng)求處理類FinalRequestProcessor的processRequest方法來(lái)調(diào)用的
客戶端是以zooKeeper.getData方法來(lái)測(cè)試的,所以直接到getData
org.apache.zookeeper.server.FinalRequestProcessor#processRequest


image.png

org.apache.zookeeper.server.FinalRequestProcessor#handleGetDataRequest


image.png

org.apache.zookeeper.server.ZKDatabase#getData
image.png

org.apache.zookeeper.server.DataTree#getData
image.png

org.apache.zookeeper.server.watch.WatchManager#addWatch


image.png

org.apache.zookeeper.server.watch.WatchManager#addWatch
①、watchTable
Map<String, Set<Watcher>> 表示一個(gè)路徑有多少個(gè)客戶端Watcher(NioServerCnxn對(duì)象)
image.png

②、watch2Paths
Map<Watcher, Set<String>> 表示一個(gè)客戶端Watcher(NioServerCnxn對(duì)象)有多少個(gè)路徑
image.png

dataWatches和childWatches都是添加watchTable、watch2Paths的屬性值
dataWatches和childWatches是在DataTree創(chuàng)建對(duì)象時(shí)創(chuàng)建的,都屬于IWatchManager對(duì)象
image.png

客戶端觸發(fā)

是在SendThread線程讀取響應(yīng)readResponse時(shí)
1、添加到waitingEvents隊(duì)列
NOTIFICATION_XID = -1 是觸發(fā)WATCHER_EVENT
①、readResponse
org.apache.zookeeper.ClientCnxn.SendThread#readResponse


image.png

image.png

②、queueEvent


image.png

org.apache.zookeeper.ClientCnxn.EventThread#queueEvent
image.png

把當(dāng)前響應(yīng)事件添加到waitingEvents隊(duì)列中
2、一次性Watch與持久Watch的區(qū)別
在添加waitingEvents隊(duì)列之前,調(diào)用materialize方法根據(jù)路徑查找客戶端的Watch
org.apache.zookeeper.ZKWatchManager#materialize
image.png

image.png

dataWatches把當(dāng)前節(jié)點(diǎn)的watch給移除了,這就是為什么zooKeeper.getData方法的watch只能調(diào)用一次
而持久化節(jié)點(diǎn)并沒(méi)有移除


image.png

3、調(diào)用watch的process方法
便可以調(diào)用到客戶端自定義的監(jiān)聽(tīng)watch的process方法
org.apache.zookeeper.ClientCnxn.EventThread#run
image.png

org.apache.zookeeper.ClientCnxn.EventThread#processEvent
image.png

服務(wù)端觸發(fā)

服務(wù)端的觸發(fā)也是在請(qǐng)求處理鏈的最后一個(gè)請(qǐng)求處理類FinalRequestProcessor的processRequest方法來(lái)調(diào)用的
1、processRequest
org.apache.zookeeper.server.FinalRequestProcessor#processRequest


image.png

2、applyRequest
org.apache.zookeeper.server.FinalRequestProcessor#applyRequest


image.png

3、processTxn
org.apache.zookeeper.server.ZooKeeperServer#processTxn(org.apache.zookeeper.server.Request)
image.png

4、processTxnInDB

org.apache.zookeeper.server.ZooKeeperServer#processTxnInDB


image.png

5、processTxn
org.apache.zookeeper.server.ZKDatabase#processTxn
image.png

org.apache.zookeeper.server.DataTree#processTxn
image.png

org.apache.zookeeper.server.DataTree#processTxn
image.png

org.apache.zookeeper.server.DataTree#processTxn
image.png

6、setData
這里還是以/abc節(jié)點(diǎn)為例,開(kāi)啟一個(gè)客戶端修改/abc的值。調(diào)用命令set /abc xxx。直接到setData
這里可以看到修改前、修改后的數(shù)據(jù)、路徑、zxid等信息

org.apache.zookeeper.server.DataTree#setData


image.png

觸發(fā)NodeDataChanged事件類型
image.png

7、triggerWatch
org.apache.zookeeper.server.watch.WatchManager#triggerWatch
image.png

org.apache.zookeeper.server.watch.WatchManager#triggerWatch
可以看到當(dāng)前路徑(/abc)下的上下文客戶端對(duì)象
image.png

org.apache.zookeeper.server.watch.WatchManager#triggerWatch
這里調(diào)用了遞歸的文件,最終的效果就是查找當(dāng)前路徑下的客戶端對(duì)象
image.png

image.png

遍歷Watch對(duì)象的process方法
image.png

8、process
org.apache.zookeeper.server.NIOServerCnxn#process
image.png

響應(yīng)頭設(shè)置ClientCnxn.NOTIFICATION_XID,這里與客戶端讀取響應(yīng)頭相對(duì)應(yīng)
9、sendResponse
發(fā)送響應(yīng)數(shù)據(jù)到客戶端
org.apache.zookeeper.server.NIOServerCnxn#sendResponse
image.png
EventType事件類型

None、NodeCreated(節(jié)點(diǎn)創(chuàng)建)、NodeDeleted(節(jié)點(diǎn)刪除)、NodeDataChanged(節(jié)點(diǎn)數(shù)據(jù)修改)、NodeChildrenChanged(孩子節(jié)點(diǎn)改變)、DataWatchRemoved(監(jiān)聽(tīng)器Watch移除)、ChildWatchRemoved(孩子監(jiān)聽(tīng)器Watch移除)、PersistentWatchRemoved(持久化的監(jiān)聽(tīng)器Watch移除)


image.png

總結(jié):

根據(jù)客戶端使用不同的API觸發(fā)不同的監(jiān)聽(tīng)器Watch。
客戶端的注冊(cè)是在SendThread線程和觸發(fā)是在EventThread線程
服務(wù)端的注冊(cè)和觸發(fā)都是在請(qǐng)求處理鏈FinalRequestProcessor的processRequest方法內(nèi)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容