ZooKeeper基礎知識總結
數據模型
ZooKeeper數據模型是一個樹狀的數據結構,類似於文件系統;和文件系統的區別在於樹中的每一個節點(葉子節點與非葉子節點)都可以保存數據,且每個節點的訪問都必須從根節點開始,以斜線作為分隔的訪問路徑,如 /root/a/b/,它沒有相對路徑的概念,所有的節點都必須通過絕對路徑來訪問;
Znode
ZooKeeper樹中的節點被稱之為znode,znode維護了一個stat結構,其中包含了版本號和時間戳;版本號是一直遞增的,每一次znode中包含的數據被更新,版本號也會發生改變;
當客戶端嘗試去更新或者刪除一個znode的時候,必須提供它要更新/刪除的znode的當前版本號,如果版本號不正確,這個更新/刪除就會失敗(有點類似於數據庫操作的樂觀鎖)。
觀察者
客戶端可以給znode添加一個觀察者(類似於事件),當znode發生改變時,這個觀察者會被觸發,相應的客戶端就會收到一個通知;
Zookeeper客戶端可以給三個操作設置觀察者:exists、getChildren、getData:
操作 | 觸發的時間點 |
getChildren |
當znode的子節點被創建或者刪除、當znode自身被刪除時觸發 |
exists | 當znode被創建、刪除,或者數據被更新時觸發 |
getData | 當znode被刪除或znode的數據被更新時觸發 |
觀察者只會被觸發一次,如果想被多次觸發,則需要在觸發之後重新註冊;觀察者的常用地方在於,使用ZooKeeper作為一個配置中心,各個客戶端(應用程序)通過觀察者監聽znode從而獲取最新的配置;
順序性Znode
當創建一個Znode時,你可以要求ZooKeeper添加一個單調遞增的計數器到這個znode上,這樣你就可以在同一個父節點下創建多個相同的znode,而每個znode會以一串數字結尾,並單調遞增;
這個計數器只在同一個父節點下唯一,最大值為2147483647,超過之後則會溢出;
暫時性Znode
Znode包含兩種類型:暫時性znode和持久性znode;當創建這個znode的客戶端session超時時,暫時性znode會被刪除,而持久性的znode與客戶端session無關,只能被顯式的刪除;
暫時性Znode不能有子節點,但它對所有的客戶端是可見的;
順序性Znode和暫時性Znode相結合可以作為分佈式鎖,具體操作為:創建順序性znode的最小值的客戶端作為分佈式鎖的獲得者,當這個客戶端關閉Session時,其創建的znode會被刪除,而剩下的順序性znode最小值的創建者將捕獲這個分佈式鎖;為避免驚群效應,每一個客戶端只需要在比它稍小的那個znode上設置一個觀察者,這樣當znode被刪除時,只會喚醒一個客戶端。
一致性
選舉
ZooKeeper使用Master/Slave模式,通過ZAB算法實現Leader的選舉機制;
ZooKeeper的所有機器可以分為三類:Leader、Follower、Learner,Learner主要用於同步Znode數據,因此選舉主要在多個Follower之間進行;目的主要在多個Follower中選舉出持有zxid和myid(ZooKeeper服務器的標識ID)相對較大(超過過半數的zxid+myid即可)的那個機器作為Leader;
在ZooKeeper集群中的每一個更新操作都會有一個全局性的唯一性標識,這個標識叫做zxid,又稱之為ZooKeeper的事務ID,它永遠是遞增的;
Zxid是一個64位的數字,包含兩部分:任期(epoch)和計數器(counter),高32位為任期,低32位為計數器;當一個新的Leader選舉出來之後,任期會加1,在同一個Leader任期內保持計數器遞增,通過此種方式記錄操作的順序性。
ZAB算法的核心在於多個Follower之間兩兩比較,如果一個Follower的zxid + myid比n/2+1(n為Follower的總數)個Follower都大,則會被選舉出來作為Leader;
正因為選舉需要比較過半數的Follower,如果過半數的Follower宕機,則集群崩潰。
寫操作
ZooKeeper集群的寫操作都是由Leader來完成的,然後再通過Leader同步到Follower,Zookeeper在返回結果到客戶端之前並不會保證會同步到所有的Follower,只需要過半(n/2+1)Follower同步成功即可;
讀操作
客戶端可以連接到集群中任何一台機器進行讀操作,但不能保證都能讀到最新的數據,因此在getData之前最好調用sync操作同步最新的數據再讀取。