ZK模型分成數據模型,節點特性,版本,Watcher,ACL五個部分。
1 數據模型
樹形結構:每個節點成爲ZNode,是數據的最小單元,每個節點可以存放數據或者是子節點。
事務ID:ZXID,每次對服務器狀態進行操作,就會分配全局的事務ID
2 節點類型
根據節點生命週期長短分成持久節點,臨時節點,順序節點
持久節點:一直存在服務端,直到手動刪除。
臨時節點:生命週期是客戶端的會話失效週期,不是TCP斷開連接。臨時節點只能作爲葉子節點,不能基於臨時節點創建子節點。
順序節點:節點可能還表現爲順序特性,即節點在父節點列表中是否標記創建順序。
3 狀態信息
節點信息包含節點數據內容以及狀態信息。
czxid:reated ZXID,表示該節點被創建時的事務ID。
mzxid:Modified ZXID,表示該節點最後一次被更新時的事務ID。
ctime:表示節點被創建的時間。
mtime:表示該節點最後一次被更新時的時間。
version:數據節點的版本號。節點被創建後,被更新過的次數,即使更新的內容與原內容相同,也視爲一次更新。
cversion:子節點的版本號。
aversion:節點的ACL版本號。
ephemeralOwner:創建該臨時節點的會話的SessionID。如果該節點爲持久節點,那麼這個屬性值爲0。
dataLength:數據內容的長度。
numChildren:當前節點的子節點個數。
pzxid:表示該節點的子節點列表最後一次被修改時的事務ID。只有子節點列表變更了纔會變更pzxid,子節點內容變更不會影響pzxid。
4 Watcher數據變更通知
一對多的發佈訂閱模式,客戶端向服務端註冊watcher,監聽某一特定主題的對象,當主題對象自身發生變化時,會通知所有的訂閱者。
4.1 watcher基礎
Watcher機制包括:客戶端,客戶端WatcherManager,服務端。
客戶端向服務端註冊watcher同時會把watcher對象存入WatcherManager中,當服務端觸發Watcher事件後,會向服務端發送通知,服務端從WatcherManager中取出對應的Watcher對象,執行回調邏輯。
Watcher特性包含:
- 註冊一次性:服務端或者客戶端的watcher一旦被觸發,就會被刪除。如果需要監聽,就要反覆註冊。否則一些更新比較頻繁的節點,每次變動都要不斷地將通知反饋給客戶端,對與網絡以及服務端性能影響很大。
- 客戶端Watcher回調是串行同步的,保證了每個wathcer的順序。
- 輕量級watcher。WatchedEvent是Watcher機制的最小通知單元,只包含了通知狀態,事件類型,節點路徑,不給出具體的變化內容,需要客戶端自己去相應節點獲取變化的內容,保證了客戶端服務端交互的數據量級。
4.2 Watcher事件
注意:
NodeDataChanged:與dataVersion一致,即使變更內容前後一樣,也會觸發此事件。
NodeChildrenChanged:所關注的節點的子節點列表有變化。這裏說的變化是指子節點的個數和組成,具體到子節點內容的變化是不會通知的。
4.3 process回調方法
WatchEvent包含三個屬性:事件狀態keeperstate,事件類型eventType,節點路徑path。
abstract public void process(WatchedEvent event);
/**
* A WatchedEvent represents a change on the ZooKeeper that a Watcher
* is able to respond to. The WatchedEvent includes exactly what happened,
* the current state of the ZooKeeper, and the path of the znode that
* was involved in the event.
*/
@InterfaceAudience.Public
public class WatchedEvent {
final private KeeperState keeperState;
final private EventType eventType;
private String path;
}
4.4 Watcher工作機制
watcher註冊機制包括:客戶端註冊Watcher,服務端處理Watcher,客戶端回調Watcher。
4.4.1 客戶端註冊Watcher
1. 創建zk客戶端對象實例時註冊watcher,這個 Watcher 將作爲整個 ZooKeeper 會話期間的默認 Watcher,它會一直被保存在客戶端 ZKWatchManager 的 defaultWatcher 裏面。(getData, getChildren, exists方法中也可以註冊watcher)。
2. 例如getData註冊Watcher後,客戶端會向當前的request標記,設置爲“使用watcher監聽”,同時封裝WatcherRegistration對象用於暫時保存數據節點路徑和wathcer對應關係。
3. WatchRegistration被封裝成Packet對象,放入發送隊列等待客戶端發送。客戶端沒有把Watcher對象發送給服務端,只是將request與requestHeader兩個屬性序列化傳輸,否則服務端就容易出現內存緊張甚至溢出的危險。
4. ZKWatcherManager.dataWatches是Map<String, Set<Watcher>>保存數據節點路徑與Watcher對象關係。
4.4.2 服務端處理Watcher
對於註冊 Watcher 請求
,FinalRequestProcessor 的 ProcessRequest 方法會判斷當前請求是否需要註冊 Watcher,如果爲 true,就會將當前的 ServerCnxn 對象和數據節點路徑傳入 getData 方法中去。ServerCnxn 是一個 ZooKeeper 客戶端和服務器之間的連接接口,代表了一個客戶端和服務器的連接,我們後面講到的 process 回調方法,實際上也是從這裏回調的,所以可以把 ServerCnxn 看作是一個 Watcher 對象。數據節點的節點路徑和 ServerCnxn 最終會被存儲在 WatchManager 的 watchTable 和 watch2Paths 中。
WatchManager 負責 Watcher 事件的觸發,它是一個統稱,在服務端 DataTree 會託管兩個 WatchManager,分別是watchTable和 watch2Paths,分別對應數據變更 Watcher 和節點變更 Watcher。
當DataTree中節點數據內容或版本發生變化或節點變更時
,會調用相應方法去觸發 WatchManager 的 triggerWatch 方法,該方法返回 ZNODE 的信息,自此進入到回調本地 process 的序列。
4.4.3 客戶端回調Watcher
SendThread的response()方法負責接收這個客戶端事件通知。首先會對replyHeader中xid進行判斷,如果是-1,則說明是一個通知類型的響應。作以下處理:
1.反序列化:ZooKeeper客戶端接到請求後,首先將字節流轉換成WatcherEvent對象。
2.處理chrootPath:如果客戶端設置了chrootPath屬性,那麼需要對服務端傳過來的完整的節點路徑進行chrootPath處理,生成客戶端的一個相對節點路徑。
3.還原WatchedEvent:將WatcherEvent對象轉換成WatchedEvent。
4.回調Watcher:將WatchedEvent對象交給EventThread線程,在下一個輪詢週期中進行Watcher回調。
5 ACL保障數據安全
用於對節點的權限進行控制,一個有效的ACL信息包含:權限模式(Scheme),授權對象(ID),權限(Permission),即"scheme:ID:permission"。
參考:
https://www.cnblogs.com/shamo89/p/9787176.html
圖比較詳細