本文主要講述Zookeeper的內部原理以及ZAB協議,Zookeeper算是大數據中的一個協做框架,比較簡單,本文應該是Zookeeper部分的最後一篇文章。關注專欄《破繭成蝶——大數據篇》,查看更多相關的內容~html
目錄node
1.1 節點類型服務器
1.3 監聽器session
2、ZAB協議異步
2.1 ZAB協議是什麼分佈式
1、Zookeeper的內部原理
1.1 節點類型
Zookeeper的節點類型能夠分爲兩種:持久型和短暫型。持久型指當客戶端與服務器斷開鏈接後,該節點不會刪除;短暫型指當客戶端與服務器斷開鏈接後,該節點也會隨之刪除。
1.2 Stat結構體
Stat結構體在《二11、Zookeeper的命令行操做》中已經有提到過了,可是這裏得再次不厭其煩的說一下。
(1)cZxid:建立節點的事務zxid。每次修改ZooKeeper狀態都會收到一個zxid形式的時間戳,也就是ZooKeeper事務ID。事務ID是ZooKeeper中全部修改總的次序。每一個修改都有惟一的zxid,若是zxid1小於zxid2,那麼zxid1在zxid2以前發生。
(2)ctime:znode被建立的毫秒數(從1970年開始)。
(3)mZxid:znode最後更新的事務zxid。
(4)mtime:znode最後修改的毫秒數(從1970年開始)。
(5)pZxid:znode最後更新的子節點zxid。
(6)cversion:znode子節點變化號,znode子節點修改次數。
(7)dataVersion:znode數據變化號。
(8)aclVersion:znode訪問控制列表的變化號。
(9)ephemeralOwner:若是是臨時節點,這個是znode擁有者的session id。若是不是臨時節點則是0。
(10)dataLength:znode的數據長度。
(11)numChildren:znode子節點數量。
1.3 監聽器
一、首先在main()線程中建立Zookeeper客戶端,這時會同時建立兩個線程:一個用於網絡鏈接通訊(A),一個用於監聽(B)。
二、經過A線程將註冊的監聽事件發送個Zookeeper,這時Zookeeper會將註冊的監聽事件添加到註冊監聽器列表。
三、Zookeeper監聽到有數據或者路徑等等的變化,就會將這個消息發送給B線程。
1.4 寫數據流程
一、客戶端向Zookeeper的服務器上寫數據,首先會發送一個寫請求。
二、若是接收到該請求的服務器(A)不是Leader服務器,那麼它會將這個請求轉發給Leader服務器,這時Leader服務器會將請求廣播給集羣內的其餘服務器。各個服務器會將寫請求加入待寫隊列,並向Leader服務器發送成功的信息。
三、當Leader服務器收到半數以上的Follower服務器的成功信息後,說明該寫操做能夠執行。這是Leader會向各個Follower發送提交信息,各個Follower收到信息後,會落實隊列裏面的寫請求,此時寫入成功。
四、服務器A通知客戶端數據寫入成功。
1.5 Zookeeper的選舉機制
選舉機制遵循半數機制,即:集羣中半數以上機器存活,集羣就是可用狀態,因此Zookeeper適合安裝奇數臺服務器。Zookeeper雖然在配置文件中並無指定Master和Slave。可是,Zookeeper工做時,是有一個節點爲Leader,其餘則爲Follower,Leader是經過內部的選舉機制臨時產生的。例若有五臺服務器(A-E)組成的Zookeeper集羣,同時它們都是最新啓動的,也就是沒有歷史數據,在存放數據量這一點上,都是同樣的。假設這些服務器依次啓動,那麼會發生下面的狀況:
一、服務器A啓動,發起一次選舉。服務器A投本身一票。此時服務器A票數一票,不夠半數以上(3票),選舉沒法完成,服務器A狀態保持爲LOOKING。
二、服務器B啓動,再發起一次選舉。服務器A和B分別投本身一票並交換選票信息:此時服務器A發現服務器B的ID比本身目前投票推舉的(服務器A)大,更改選票爲推舉服務器B。此時服務器A票數0票,服務器B票數2票,沒有半數以上結果,選舉沒法完成,服務器A、B狀態保持LOOKING。
三、服務器C啓動,發起一次選舉。此時服務器A和B都會更改選票爲服務器C。這次投票結果:服務器A爲0票,服務器B爲0票,服務器C爲3票。此時服務器C的票數已經超過半數,服務器C當選Leader。服務器A、B更改狀態爲FOLLOWING,服務器C更改狀態爲LEADING。
四、服務器D啓動,發起一次選舉。此時服務器A、B、C已經不是LOOKING狀態,不會更改選票信息。交換選票信息結果:服務器C爲3票,服務器D爲1票。此時服務器D服從多數,更改選票信息爲服務器C,並更改狀態爲FOLLOWING。
五、服務器E啓動,過程同4。
2、ZAB協議
2.1 ZAB協議是什麼
ZAB協議的全稱是Zookeeper Atomic Broadcast(Zookeeper原子廣播)。Zookeeper是經過ZAB協議來保證分佈式事務的最終一致性。ZAB協議是爲分佈式協調服務Zookeeper專門設計的一種支持崩潰恢復的原子廣播協議,是Zookeeper保證數據一致性的核心算法。ZAB借鑑了Paxos算法,但又不像Paxos算法那樣,是一種通用的分佈式一致性算法。它是特別爲Zookeeper設計的支持崩潰恢復的原子廣播協議。
在Zookeeper中主要依賴ZAB協議來實現數據一致性,基於該協議,Zookeeper實現了一種主備模型(即Leader和Follower模型)的系統架構來保證集羣中各個副本之間數據的一致性。這裏的主備系統架構模型,就是指只有一臺客戶端(Leader)負責處理外部的寫事務請求,而後Leader客戶端將數據同步到其餘Follower節點。Zookeeper客戶端會隨機的連接到Zookeeper集羣中的一個節點,若是是讀請求,就直接從當前節點中讀取數據;若是是寫請求,那麼節點就會向Leader提交事務,Leader接收到事務提交,會廣播該事務,只要超過半數節點寫入成功,該事務就會被提交。
ZAB協議的特性:
一、ZAB協議須要確保那些已經在Leader服務器上提交的事務最終被全部的服務器提交。
二、ZAB協議須要確保丟棄那些只在Leader上被提出而沒有被提交的事務。
2.2 ZAB協議的做用
一、當主進程出現異常的時候,整個Zookeeper集羣依舊可以正常工做。
二、使用一個Leader來接收並處理客戶端的事務請求,並採用ZAB的原子廣播協議,將服務器數據的狀態變動以事務proposal(事務提議)的形式廣播到全部的Follower進程上去。
三、保證一個全局的變動序列被順序引用。Zookeeper是一個樹形結構,不少操做都要先檢查才能肯定是否能夠執行,爲了保證這一點,ZAB要保證同一個Leader發起的事務要按順序被請求,同時還要保證只有先前Leader的事務被請求以後,新選舉出來的Leader才能再次發起事務。
2.3 ZAB協議的原理
ZAB協議要求每一個Leader都要經歷三個階段:發現、同步、廣播。
發現階段要求Zookeeper集羣必須選舉出一個Leader,同時Leader會維護一個Follower可用客戶端列表。未來客戶端能夠和這些Follower節點進行通訊。同步階段Leader要負責將自己的數據與Follower完成同步,作到多副本存儲。Follower將隊列中未處理完的請求消費完成後,寫入本地事務日誌中。廣播階段Leader能夠接受客戶端新的事務Proposal請求,將新的Proposal請求廣播給全部的Follower。
ZAB協議定義了事務請求的處理方式:全部的事務請求必須由一個全局惟一的服務器來協調處理,這樣的服務器被叫作Leader服務器。其餘剩餘的服務器則是Follower服務器。Leader服務器負責將一個客戶端事務請求,轉換成一個事務Proposal,並將該Proposal分發給集羣中全部的Follower服務器,也就是向全部 Follower節點發送數據廣播請求。分發以後Leader服務器須要等待全部Follower服務器的反饋,在ZAB協議中,只要超過半數的Follower服務器進行了正確的反饋後,那麼Leader就會再次向全部的Follower服務器發送Commit消息,要求其將上一個事務proposal進行提交。這也就是上文中1.4提到的寫數據流程。
2.4 ZAB協議的工做
當整個集羣啓動過程當中,或者當Leader服務器出現網絡中弄斷、崩潰退出或重啓等異常時,ZAB協議就會進入崩潰恢復模式,選舉產生新的Leader。當選舉產生了新的Leader,同時集羣中有過半的機器與該Leader服務器完成了狀態同步(即數據同步)以後,ZAB協議就會退出崩潰恢復模式,進入消息廣播模式。這時,若是有一臺遵照ZAB協議的服務器加入集羣,由於此時集羣中已經存在一個Leader服務器在廣播消息,那麼該新加入的服務器自動進入恢復模式:找到Leader服務器,而且完成數據同步。同步完成後,做爲新的Follower一塊兒參與到消息廣播流程中。
當Leader出現崩潰退出或者機器重啓,亦或是集羣中不存在超過半數的服務器與Leader保存正常通訊,ZAB協議就會再一次進入崩潰恢復,發起新一輪Leader選舉並實現數據同步。同步完成後又會進入消息廣播模式,接收事務請求。在整個消息廣播中,Leader會將每個事務請求轉換成對應的proposal來進行廣播,而且在廣播事務Proposal以前,Leader服務器會首先爲這個事務Proposal分配一個全局單遞增的惟一ID,稱之爲事務ID(即zxid),因爲ZAB協議須要保證每個消息的嚴格的順序關係,所以必須將每個proposal按照其zxid的前後順序進行排序和處理。
2.4.1 消息廣播
消息廣播的步驟以下:
一、客戶端發起一個寫操做請求。
二、Leader服務器將客戶端的請求轉化爲事務Proposal提案,同時爲每一個Proposal分配一個全局的ID,即zxid。
三、Leader服務器爲每一個Follower服務器分配一個單獨的隊列,而後將須要廣播的Proposal依次放到隊列中去,而且根據FIFO策略進行消息發送。
四、Follower接收到Proposal後,會首先將其以事務日誌的方式寫入本地磁盤中,寫入成功後向Leader反饋一個Ack響應消息。
五、Leader接收到超過半數以上Follower的Ack響應消息後,即認爲消息發送成功,能夠發送commit消息。
六、Leader向全部Follower廣播commit消息,同時自身也會完成事務提交。Follower接收到commit消息後,會將上一條事務提交。
Zookeeper採用ZAB協議的核心,就是隻要有一臺服務器提交了Proposal,就要確保全部的服務器最終都能正確提交Proposal。Leader服務器與每個Follower服務器之間都維護了一個單獨的FIFO消息隊列進行收發消息,使用隊列消息能夠作到異步解耦。Leader和Follower之間只須要往隊列中發消息便可。若是使用同步的方式會引發阻塞,性能要降低不少。
2.4.2 崩潰恢復
一旦Leader服務器出現崩潰或者因爲網絡緣由致使Leader服務器失去了與過半Follower的聯繫,那麼就會進入崩潰恢復模式。在ZAB協議中,爲了保證程序的正確運行,整個恢復過程結束後須要選舉出一個新的Leader服務器。
ZAB協議崩潰恢復要求知足兩個要求:一、確保已經被Leader提交的Proposal必須最終被全部的Follower服務器提交。二、確保丟棄已經被Leader提出的可是沒有被提交的Proposal。根據上述要求ZAB協議須要保證選舉出來的Leader知足如下條件:一、新選舉出來的Leader不能包含未提交的Proposal。即新選舉的Leader必須都是已經提交了Proposal的Follower服務器節點。二、新選舉的Leader節點中含有最大的zxid。
2.5 ZAB數據同步
一、完成Leader選舉後新的Leader具備最高的zxid,在正式開始工做以前(接收事務請求,而後提出新的Proposal),Leader服務器會首先確認事務日誌中的全部的Proposal是否已經被集羣中過半的服務器Commit。
二、Leader服務器須要確保全部的Follower服務器可以接收到每一條事務的Proposal,而且能將全部已經提交的事務Proposal應用到內存數據中。等到Follower將全部還沒有同步的事務Proposal都從Leader服務器上同步過來而且應用到內存數據中之後,Leader纔會把該Follower加入到真正可用的Follower列表中。
在ZAB的事務編號zxid設計中,zxid是一個64位的數字。其中低32位能夠當作一個簡單的單增計數器,針對客戶端每個事務請求,Leader在產生新的Proposal事務時,都會對該計數器加1。而高32位則表明了Leader週期的epoch編號。epoch編號能夠理解爲當前集羣所處的年代或者週期。每次Leader變動以後都會在epoch的基礎上加1,這樣舊的Leader崩潰恢復以後,其餘Follower也不會聽它的,由於Follower只服從epoch最高的Leader命令。每當選舉產生一個新的Leader,就會從這個Leader服務器上取出本地事務日誌中最大編號Proposal的zxid,並從zxid中解析獲得對應的epoch編號,而後再對其加1,以後該編號就做爲新的epoch值,並將低32位數字歸零,由0開始從新生成zxid。ZAB協議經過epoch編號來區分Leader變化週期,可以有效避免不一樣的Leader錯誤的使用了相同的zxid編號提出了不同的Proposal的異常狀況。基於以上策略當一個包含了上一個Leader週期中還沒有提交過的事務Proposal的服務器啓動時,當這臺機器加入集羣中,以Follower角色連上Leader服務器後,Leader服務器會根據本身服務器上最後提交的Proposal來和Follower服務器的Proposal進行比對,比對的結果確定是Leader要求Follower進行一個回退操做,回退到一個確實已經被集羣中過半機器Commit的最新Proposal。
到這本文基本上接近尾聲了,這篇文章理論描述居多,可能會比較枯燥,大家有什麼問題,歡迎留言,讓我看看大家都有哪些問題~