1. 程式人生 > >Zookeeper的watcher資料變更通知機制

Zookeeper的watcher資料變更通知機制

在zookeeper中,引入了watcher機制來通知客戶端,服務端的節點資訊發生了變化。其允許客戶端向服務端註冊一個watcher監聽,

當服務端的一些指定事件觸發了這個watcher,就會向指定的客戶端傳送一個事件通知。

zookeeper的watcher機制主要包括客戶端執行緒、客戶端watchermanager和zookeeper伺服器三部分。其具體工作流程為,

客戶端在向zookeeper伺服器註冊watcher的同時,會將watcher物件儲存在客戶端的watchermanager中。當服務端觸發watcher事件後,

會向客戶端傳送通知,客戶端執行緒從watchermanager中取出對應的watcher物件,根據通知型別和節點路徑,來處理回撥邏輯,對客戶端資料做出相應處理。

watch工作機制

zookeeper的工作機制主要包括三個步驟:客戶端註冊watcher、服務端處理watcher和客戶端回撥watcher事件。

首先需要了解一下zookeeper中的watchedevent結構,其包括三個基本屬性:通知狀態(keepstate)、事件型別(eventType)和節點路徑(path)。

zookeeper使用watchedevent物件來封裝服務端事件並傳遞給watcher,而實際傳遞的是watcherevent,其結構和watchedevent一樣,

只是其實現了序列化,可以在網路上傳輸。從這裡可以看出,watcher事件只是一個簡單的事件說明,並不包含事件的資料變更內容,

這樣能保證網路傳輸的高效性。

客戶端註冊watcher

在通過客戶端介面呼叫時,可以指定一個watcher介面,以接受伺服器事件的回撥。在註冊watcher即可後,客戶端首先會對當前客戶端請求request進行標記,

將其設定為“使用watcher監聽”,同時會封裝一個watcher的註冊資訊watchregistration物件,用於暫時儲存資料資料節點和watcher的物件關係。

由於zookeeper中的最小通訊單元為packet,因此,在clientCnxn中watchregistration又會被封裝到Packet中,然後放入傳送佇列中等待客戶端傳送。隨後,

客戶端會想服務端傳送請求,並等待請求返回。完成請求之後,客戶端的SendThread執行緒的readresponse方法負責接收服務端的請求,

並將接收到的packet中的watcher註冊到ZKWatcherManager中,並最終儲存到dataWatchers中,用於服務端事件的回撥的時候獲取對應節點的對應watcher事件。

服務端處理watcher

從上面的分析,我們可以知道,客戶端註冊的watcher並不會傳遞到服務端,只是在客戶端進行了watcher的儲存,所以服務端接受到watch註冊事件之後,

需要將該事件進行封裝,在服務端也進行儲存。

ServerCnxn儲存

我們知道ServerCnxn是服務端與客戶端進行網路互動的一個介面,代表了客戶端與服務端的連線。其底層採用netty實現。所以,在接受到註冊請求之後,服務端會將ServerCnxn物件和資料階段路徑儲存到WatchManager的watchTable和watch2Paths中。方便事件觸發時的呼叫。

watcher觸發

在對指定的節點發生相關的事件時,通過呼叫WatchManager的triggerWatch方法觸發相關的事件。其通過將節點資訊和事件型別進行封裝成為watchedevent,

並查詢到到對應節點的註冊的watcher,然後分別呼叫watcher的回撥函式process。而在process函式中其實就是通過封裝的ServerCnxn

向客戶端傳送watchedevent資料請求。具體的watcher業務處理則在客戶端處理。

客戶端回撥watcher

上面我們分析了,服務端並不處理watcher事件的具體邏輯,只是將事件通知傳送到客戶端。下面分析客戶端是如何處理服務端傳送回來的事件通知的。

SendThread接收事件通知

SendThread是客戶端開啟的與服務端建立TCP長連線的執行緒,它會一直保持連線狀態,採用心跳監測的方式確保與服務端的連線存活。

在客戶端的SendThread中,當接收到服務端請求之後,會將請求反序列化成watchedevent物件,並將watchedevent物件轉換為watcherevent物件,

最後將watcherevent物件新增到EventThread執行緒,完成對watcher的回撥。

EventThread是客戶端的一個專門處理watcher時間的執行緒,其保持了一個待處理事件的佇列。它根據傳遞的事件的型別和節點資訊,

從客戶端的ZKWatcherManager中取出相關的watcher,將其新增到EventThread事件佇列中,並在去run方法中不斷取出watcher事件進行處理。

但是,這裡需要注意一點就是,(1)事件註冊是一次性的,因為在每次處理事件之後,就會將相應的watcher註冊刪除;(2)客戶端接收到的服務端watcher事件中

並不包含事件更改的具體內容,只是告知發生了這樣一個watcher事件,所以,客戶端在接收到watcher事件之後,需要在回撥函式process中對服務端的資料進行重新獲取,

才能獲得更改的具體內容。