概述
本文的主要目的是分析zookeeper的整個資料寫入過程,相信大家或多或少都聽說過zookeeper是一個集中式的單點寫入過程,所有的寫入請求都會轉發到Leader來完成資料的寫入過程,而且在整個寫入過程當中會涉及到二次送出(proposal/commit)過程,希望通過這篇文章能夠幫助感興趣的人建立一個整體的流程印象。
延伸閱讀關于Paxos的協定可以閱讀延伸的文章《
拜占庭将軍問題》,其實zookeeper的二階段送出就是這個模型的實作,公式證明看不懂但是思路可以看得懂。
最後整個文章讀起來比較費力,如果有興趣真正搞懂整個寫入過程,還是需要抽出一整塊時間來閱讀的,我本人這篇文章從理清楚過程到畫圖大概花了一個星期左右,這還是建議閱讀别人的文章的基礎上的,參考文章中列出的幾篇文章還是非常不錯的,可以互相補充着來看,因為整個過程涉及的代碼太多了,是以就建議大家看參考文獻中的文章吧,雖然有一些小出入但是整體來說是非常全面的。
zookeeper中涉及的事務操作主要包括下面幾大類:
1)寫操作(OpCode.create,OpCode.delete,OpCode.setData,OpCode.setACL)
2)Session的建立和關閉操作(OpCode.createSession和OpCode.closeSession)
3)OpCode.multi操作。
過程分析
在正式進入過程分析之前,先得有一個宏觀的印象,那就是zookeeper的寫入過程當中,當我們連接配接的是Follower的對象的時候,寫入會轉發到Leader,最後由Leader完成寫入并同步到所有Follower當中,Follower是不具備處理資料寫入功能,Follower其實隻是對寫入的一個轉發而已,從下面這個圖檔就可以看明白了。
資料寫入過程
另外,在zookeeper的FollowerZookeeperServer和LeaderZookeeperServer當中,都有一個調用鍊的概念,在接收封包後會通過調用鍊進行處理後回送封包,其中leader端和Follower端的調用鍊是有差別的,具體差别就是下圖的樣子。
Leader調用鍊
Follower調用鍊
在整個互動過程中比較核心的兩類封包,Request對象是調用鍊處理過程中傳輸的對象,QuoromPacket是follower和leader互動過程涉及的封包。
Request封包
QuorumPacket封包
整個核心的資料寫入過程都在下面這個圖當中,核心的關注點要關注幾個角色之間互動封包以及兩階段送出過程。
zookeeper寫入過程
下面過程分析的數字編号不是對應上圖當中的編号,而是宏觀上按順序把整個過程進行分解,當然每個過程都是可以在上圖中找到對應的連接配接線的(源碼層面可以看
ZooKeeper源碼分析:Quorum請求的整個流程)。
1、client向follower發送packet封包,然後進入follower的消息處理鍊當中,也就是FollowerRequestProcessor當中。
2、Follower的處理過程:FollowerRequestProcessor做兩個事情:負責沿着調用鍊處理也就是執行CommitProcessor當中,在這個時候follower的處理就暫時停留在了CommitProcessor當中;負責将封包通過follower.request()發送到leader當中,此時封包的type為
Leader.REQUEST。
3、Leader的處理過程:Leader端由LearnerHandler(負責和follower建立的連接配接)進行處理,核心處理邏輯其實就兩個:邏輯一依次通過調用鍊PrepRequestProcessor -> ProposalRequestProcessor->SyncRequestProcessor(CommitProcessor),其中
CommitProcessor其實處理到一半沒有繼續往下執行;邏輯二是PrepRequestProcessor -> ProposalRequestProcessor->發送
Leader.PROPOSAL封包給Follower。
4、Follower的處理過程:Follower在接收到Leader的Proposal封包以後,通過調用鍊SyncRequestsProcessor->SendAckRequestProcessor發送Leader.ACK封包給Leader。
5、Leader的處理過程:Leader在收到Follower的ack封包以後,會判斷是否超過半數已經回複了相應封包,也就是對應的tryToCommit的處理邏輯,裡面其實就是判斷是否超過半數的follower回複了,如果超過半數回複了那麼就進入了
第二個階段(Commit/Inform)階段發送給Follower,當然leader本身會在之前的CommitProcessor當中繼續操作(也就是在步驟3當中執行到一半的過程),沿着調用調用CommitProcessor->ToBeAppliedRequestProcessor->FinalRequestProcessor完成資料的寫入。
6、Follower收到Leader.COMMIT/INFORM封包之後開始進行資料的持久化,并将響應封包發送給client,整個過程就結束了。