“ 知之為知之,不知為不知,是知也。”
01、角色
-
Leader:
主要負責處理事務相關的操作,負責給Follower釋出命令,處理Follower的反饋資訊
負責同步訊息,將訊息同步到Follower中
可以保證事務處理的順序性
負責投票的發起以及更新系統的狀態
-
Follower:
負責參與投票選舉Leader
參與事務的Proposal請求的投票
將事務的執行結果反饋給Leader
-
Observer:
作為觀察者不參與Leader的選舉
負責將客戶端的寫請求轉發給Leader
02、會話
-
會話是指zookeeper伺服器與客戶端的會話,在zookeeper中一個客戶端連線是指客戶端與服務端之間的TCP長連線。
-
客戶端啟動時首先會與伺服器簡歷一個TCP建立一個連線,從建立這個連線開始,客戶端會話的生命週期就開始了。
-
通過這個連線客戶端可以通過心跳檢測來保證與服務端之間的會話,也能夠向zookeeper伺服器傳送請求並接受響應,還可以接收伺服器的Watch事件通知。
-
如果因為故障等原因導致客戶端連線斷開,那麼在sessionTimeout規定的時間內能夠重新連線上叢集中的任意一臺,那麼之前的會話仍然有效。
-
為客戶端建立連線之前服務端會為客戶端分配一個sessionID,並且sessionID是唯一的。
03、節點
-
臨時節點:臨時節點的生命週期和客戶端與服務端的會話進行保定,如果客戶端會話失效,那麼這個客戶端建立的所有臨時節點也會被移除。
-
持久節點:一旦ZNode被建立除非執行ZNode移除操作,否則ZNode一直儲存在zookeeper上。
-
zookeeper將資料都儲存在記憶體中,儲存資料的模型是以一棵樹的形式進行儲存的
-
在ZNode中,zookeeper都會為每個ZNode維護一個叫做Stat的資料結構,Stat中記錄ZNode的三個資料版本,分別是:
1、version(當前ZNode版本)
2、cversion(當前ZNode子節點的版本)
3、aversion(當前ZNode的ACL版本)
04、Watcher(監聽)
-
使用者使用zookeeper時可以在指定節點上註冊Watcher,並且當有特定事件觸發了這個Watcher時,zookeeper服務端會將這個事件通知到指定的客戶端中。
-
watch事件是一次性的,觸發結束就會消失。
-
流程如下:
Watch是輕量級的,其實就是本地JVM的Callback,伺服器端只是存了是否有設定了Watcher的布林型別。(原始碼見:org.apache.zookeeper.server.FinalRequestProcessor)
在服務端,在FinalRequestProcessor處理對應的Znode操作時,會根據客戶端傳遞的watcher變數,新增到對應的ZKDatabase(org.apache.zookeeper.server.ZKDatabase)中進行持久化儲存,同時將自己NIOServerCnxn做為一個Watcher callback,監聽服務端事件變化
Leader通過投票通過了某次Znode變化的請求後,然後通知對應的Follower,Follower根據自己記憶體中的zkDataBase資訊,傳送notification資訊給zookeeper客戶端。
Zookeeper客戶端接收到notification資訊後,找到對應變化path的watcher列表,挨個進行觸發回撥。
05、ACL
zookeeper採用了ACL策略來實現許可權控制,這個ACL策略類似於UNIX檔案系統的許可權控制。
五種許可權分別為:
1、CREATE:建立子節點的許可權
2、READ:讀取節點資料以及子節點列表的許可權
3、WRITER:更新節點資料的許可權
4、DELETE:刪除子節點的許可權
5、ADMIN:設定節點ACL的許可權
06、特點
1、順序一致性:客戶端發出的請求會按照發出的順序傳送給zookeeper
2、原子性:zookeeper叢集要處理某個事務請求時,該事務在叢集中所有的處理結果都是一致的,也就是要麼該事務被所有zookeeper處理成功,只要有一個zookeeper沒有處理成功就全部失敗。
3、可靠性:一旦請求被應用,那麼該請求的結果就會被持久化,直到下一次的請求。
4、資料唯一性:在叢集中客戶端無論連線了哪個zookeeper獲取到的資料模型都是一樣的。
07、Zookeeper選舉流程
-
zookeeper叢集一般都是奇數臺,這是因為如果有三臺集器,那麼最多允許掛掉一臺,如果有四臺,那麼也是最多允許掛掉一臺,既然三臺 和四臺的容災能力是一樣的,那麼為了節省伺服器資源選擇奇數個數就可以。
-
在zookeeper叢集中只要有任意一臺機器收到了半數以上的投票,那麼該機器就被選舉為Leader。
-
zookeeper的選舉通常是由zxid以及myid來決定誰是Leader。
-
zxid:zxid是一個64位的有規則的編號,在64位中高32位是epoch編號,低32位是訊息計數器,每收到一條提議(proposal),低32位的訊息計數器就會加1。epoch編號是選舉Leader的計數器,也就是每次投票選舉Leader操作都會進行加1。每產生一個Leader那麼epoch都會加1並且保證了唯一性,這樣也保證了Follower只聽從最新的epoch編號對應的Leader,就算舊的Leader崩潰恢復之後也不會有其它Follower聽從這個舊Leader了。
-
myid:myid是叢集中的機器標識,在叢集中每個機器都會分配一個唯一的myid。
-
投票過程:在叢集中每個啟動的server的狀態都是LOOKING,然後開始執行選舉,每個server都會向其它server廣播投票,投票資訊中包含該server的myid和zxid(剛開始時myid和zxid都是自己),比如server1投的資訊為(1,0),server2投出的資訊為(2,0),server3投出的為(3,0)然後首先根據zxid來選舉誰是Leader,發現zxid都相同,那麼再根據myid,server1收到server2和server3的資訊,那麼根據myid會投票server3為Leader,server2收到server1和server3的,那麼也會投票server3,server3收到的投票超過半數,則選擇server3為Leader,最後立即改變叢集中各個server的狀態都為Following。(舉例比較單一也是為了方便理解,真實的投票選舉過程可以看paxos演算法選舉流程)
08、zab協議
1、崩潰恢復:當叢集中Leader宕機或者半數以上的Follower失去連線,那麼此時Leader就不是一個合法的Leader就需要重新選舉Leader,就需要進入崩潰恢復階段,崩潰恢復階段包括兩部分:Leader選舉和資料同步,Leader選舉階段負責選舉新的Leader,資料同步階段負責將Follower和Leader中的資料保持一致。
2、訊息廣播:
1、Leader收到客戶端的事務請求時會將該請求轉換為proposal,並且會為proposal生成一個唯一的zxid
2、Leader會為每一個Follower生成一個FIFO佇列,用來儲存Leader發出的proposal,並且Follower會按照FIFO順序接收(保證順序性)
3、Follower收到proposal然後將proposal寫入本地磁碟中,寫入成功後返回一個ack響應訊息給Leader。
4、Leader收到超過半數的ack響應訊息後,則認為訊息傳送成功,可以commit事務
5、Leader向所有的Follower傳送commit訊息,同時自身也會完成事務的提交。Follower收到commit訊息則將proposal事務提交。