一、zookeeper 初始化:
在Zookeeper啟動(dòng)期間,首先會(huì)進(jìn)行數(shù)據(jù)初始化工作,用于將存儲(chǔ)在磁盤(pán)上的數(shù)據(jù)文件加載到Zookeeper
服務(wù)器內(nèi)存中,主要包括了從快照文件中加載快照數(shù)據(jù)和根據(jù)事物日志進(jìn)行數(shù)據(jù)訂正兩個(gè)過(guò)程。以下是Zookeeper數(shù)據(jù)初始化的過(guò)程。

? ??1.FileTxnSnapLog是Zookeeper事務(wù)日志和快照數(shù)據(jù)訪問(wèn)層,內(nèi)容中有FileTxnLog(事務(wù)日志管理器)初始化
FileSnap(快照數(shù)據(jù)管理器)初始化。
? ??2.構(gòu)建內(nèi)存數(shù)據(jù)庫(kù)ZKDatabase,首先構(gòu)建一個(gè)初始化DataTree,創(chuàng)建一些Zookeeper默認(rèn)節(jié)點(diǎn)/./zookeeper,/zookeeper/quota
3.PlayBackListener監(jiān)聽(tīng)器主要用來(lái)接收事務(wù)應(yīng)用過(guò)程中的回調(diào)?
4.反序列化快照文件,并進(jìn)行文件的checksum校驗(yàn)以確定快照文件的正確性。
5.獲得快照最新ZXID(zxid_for_snap),獲取事務(wù)日志ZXID比zxid_for_snap大的事務(wù),將根據(jù)事務(wù)日志更新對(duì)應(yīng)的數(shù)據(jù),更新完所有事務(wù)日志將獲得事務(wù)最大ZXID(lastProcessedZxid)每當(dāng)有一個(gè)事務(wù)被應(yīng)用到內(nèi)存數(shù)據(jù)庫(kù)中去后,Zookeeper同是回調(diào)PlayBackListener監(jiān)聽(tīng)器,將這一事務(wù)操作記錄轉(zhuǎn)換成Proposal,并保存到ZKDatabase.committedLog中,以便Follower進(jìn)行快照同步。
6.epoch:紀(jì)元、時(shí)代。標(biāo)識(shí)當(dāng)前Leader周期。每次選舉產(chǎn)生一個(gè)新的Leader服務(wù)器之后,就會(huì)生成一個(gè)新的epoch。在運(yùn)行期間集群中機(jī)器相互通信的過(guò)程中,都會(huì)帶上這個(gè)epoch以確保彼此在同一個(gè)Leader周期內(nèi)。
二、zookeeper各個(gè)服務(wù)器角色:
在Zookeeper集群中,分別有Leader、Follower和Observer三種類(lèi)型的服務(wù)器角色。其中非Leader也稱(chēng)為L(zhǎng)eaner服務(wù)器。
1.Leader
Leader服務(wù)器是整個(gè)Zookeeper集群工作機(jī)制中的核心,其主要工作有以下兩個(gè):
1)事務(wù)請(qǐng)求的唯一調(diào)度和處理者,保證集群事務(wù)處理的順序性。
2)集群內(nèi)部各服務(wù)器的調(diào)度者。
?使用責(zé)任鏈模式來(lái)處理每個(gè)客戶端請(qǐng)求是Zookeeper的一大特色。
? ? 請(qǐng)求處理鏈:

非事務(wù)請(qǐng)求將直接提交給CommitProcessor否則將除了將請(qǐng)求提交給CommitProcessor外,根據(jù)請(qǐng)求類(lèi)型創(chuàng)建對(duì)應(yīng)的Proposal提議,并發(fā)送給所有的Follower服務(wù)器來(lái)發(fā)起一次集群內(nèi)的事務(wù)投票。同時(shí),講過(guò)失去請(qǐng)求交付給SynRequestProcessor進(jìn)行事務(wù)日志的記錄以及事務(wù)的快照。
LearnerHandler:
? ? 為了保持很整個(gè)內(nèi)部的實(shí)時(shí)通信,Leader服務(wù)器會(huì)與每一個(gè)Follower/Observer服務(wù)器都建立一個(gè)TCP長(zhǎng)連接,同時(shí)也會(huì)為每個(gè)Follower/Observer服務(wù)器都創(chuàng)建一個(gè)名為L(zhǎng)eanerHandler的實(shí)體。LeanerHandler是Learner服務(wù)器的管理器,主要負(fù)責(zé)Learner服務(wù)器與Leader服務(wù)器之間的網(wǎng)絡(luò)通信,包括數(shù)據(jù)同步、請(qǐng)求轉(zhuǎn)發(fā)和Proposal提議的投票等。
2.Follower
Follower服務(wù)器是Zookeeper集群的跟隨者,其主要工作有以下三個(gè):
1)處理客戶端非事務(wù)請(qǐng)求,轉(zhuǎn)發(fā)事務(wù)請(qǐng)求給Leader服務(wù)器。
2)參與事務(wù)請(qǐng)求Proposal的投票。
3)參與Leader選舉投票。
? ? ? ? 由于不需要負(fù)責(zé)對(duì)事務(wù)請(qǐng)求的投票處理,因此相對(duì)來(lái)說(shuō)Follower服務(wù)器的請(qǐng)求處理鏈會(huì)簡(jiǎn)單一些,如下:

FollowerRequestProcessor是Follower服務(wù)器的第一個(gè)請(qǐng)求處理器,其主要工作就是識(shí)別出當(dāng)前請(qǐng)求是否是事務(wù)請(qǐng)求。如果是事務(wù)請(qǐng)求則將請(qǐng)求發(fā)送給Leader服務(wù)器。
SendAckRequestProcessor承擔(dān)事務(wù)日志記錄反饋的角色,在完成事務(wù)日志記錄后,會(huì)向Leader服務(wù)器發(fā)送ACK消息以表明自身完成了事務(wù)日志的記錄工作。
3.Observer
? ? ? ? 該服務(wù)器充當(dāng)一個(gè)觀察者的角色,觀察Zookeeper 集群的最新?tīng)顟B(tài)變化并將這些狀態(tài)變更同步過(guò)來(lái),與Follower唯一區(qū)別是Observer不參與任何形式的投票,包括事務(wù)請(qǐng)求Proposal的投票和Leader選舉投票。
? ? ? ? Observer請(qǐng)求處理鏈,如下:

zookeeper leader選舉:
1.Leader選舉概述:
每個(gè)服務(wù)器都會(huì)以(myid,ZXID)的方式發(fā)起投票,每個(gè)zookeeper服務(wù)器都會(huì)有一個(gè)myid,且唯一。
? ?選舉流程:
? ? 1)每個(gè)server都會(huì)發(fā)出一個(gè)投票
? ? 2)接收來(lái)自各個(gè)服務(wù)器的投票
? ? 3)處理投票:
優(yōu)先檢查ZXID如果,其他ZXID比自己ZXID大,則更新自己的投票
如果ZXID相同,則比較myid,如果自己myid最大,則不更新自己的投票,否則將更新。
? ? 4)統(tǒng)計(jì)投票:投票過(guò)半
5)改變服務(wù)器狀態(tài)
如果運(yùn)行中Leader掛掉,則先修改非Observer服務(wù)器的狀態(tài)為L(zhǎng)ocking,在進(jìn)行Leader選舉流程。
2.Leader算法分析:
SID: ?服務(wù)器ID ,ZXID: 事務(wù)ID, Vote: 投票, Quorum: 過(guò)半機(jī)器數(shù) quorum=(n/2+1)
集群中已經(jīng)存在Leader服務(wù)器,則會(huì)被告知當(dāng)前Leader的信息,將不進(jìn)行Leader的選舉。
1)每個(gè)server都會(huì)發(fā)出(SID,ZXID)的投票
2)收到各個(gè)服務(wù)器投票(vote_sid, vote_zxid)
3) ? ?vote_zxid>self_zxid ,投票(vote_sid,vote_zxid)
vote_zxid=self_zxid,vote_sid>self_sid,投票(vote_sid,vote_zxid)
否則將不進(jìn)行投票
? ? ? 4) ? ?統(tǒng)計(jì)過(guò)半的投票
? ? ? ? 總之,通常那臺(tái)服務(wù)器上的數(shù)據(jù)越新,那么將越有可能成為L(zhǎng)eader,原因很簡(jiǎn)單,數(shù)據(jù)越新,那么它的ZXID也就越大,也就是越能夠保證數(shù)據(jù)的回復(fù)。當(dāng)然,如果集群中幾個(gè)服務(wù)器具有相同的ZXID,那么SID較大的那臺(tái)服務(wù)器成為L(zhǎng)eader。
3.Leader實(shí)現(xiàn)細(xì)節(jié):
? ? 服務(wù)器狀態(tài):QuorumPeer.ServerState狀態(tài),
LOOKING(尋找Leader狀態(tài)),F(xiàn)OLLOWING,LEADING,OBSERVING
投票數(shù)據(jù)結(jié)構(gòu):Vote(id,zxid,electionEpoch(邏輯時(shí)鐘,每進(jìn)入新一輪的投票后,都會(huì)對(duì)改制進(jìn)行加1操作)?peerEpoch被推舉的Leader的epoch?,state)
QuorumCnxManager:每臺(tái)服務(wù)器啟動(dòng)的時(shí)候,都會(huì)啟動(dòng)一個(gè)QuorumCnxManager,負(fù)責(zé)各臺(tái)服務(wù)器之間的底層Leader選舉過(guò)程中的網(wǎng)絡(luò)通信。這個(gè)類(lèi)內(nèi)部維護(hù)了一系列的隊(duì)列,用于保存接收到的、待發(fā)送的消息,以及消息的發(fā)送器。除接受隊(duì)列以外,這里提到的所有隊(duì)列都有一個(gè)共同點(diǎn)---按SID分組形成隊(duì)列集合,假設(shè)集群中除自身外還有4臺(tái)機(jī)器,那么當(dāng)前服務(wù)器就會(huì)為這4臺(tái)服務(wù)器分別創(chuàng)建一個(gè)發(fā)送隊(duì)列,互不干擾。
recvQueue: 消息接收隊(duì)列,用于存放那些從其他服務(wù)器接收到的消息。
queueSendMap:消息發(fā)送隊(duì)列,用于保存那些待發(fā)送的消息。是Map,按照SID進(jìn)行分組,分別為集群中的每臺(tái)機(jī)器分配一個(gè)單獨(dú)隊(duì)列,從而保證各臺(tái)機(jī)器之間的消息發(fā)送互不影響。
senderWorkerMap:發(fā)送器集合,每個(gè)SendWorker消息發(fā)送器,都對(duì)應(yīng)一臺(tái)遠(yuǎn)程Zookeeper服務(wù)器,負(fù)責(zé)消息的發(fā)送。
lastMessageSent:最近發(fā)送過(guò)的消息。為每個(gè)SID保留最新的發(fā)送消息。
? ? QuorumCnxManager在啟動(dòng)的時(shí)候,會(huì)創(chuàng)建一個(gè)ServerSocket來(lái)監(jiān)聽(tīng)Leader選舉的通信端口。開(kāi)啟端口監(jiān)聽(tīng)后,Zookeeper就能夠不斷的接受到來(lái)自其他服務(wù)器的創(chuàng)建連接請(qǐng)求,在接收到來(lái)自其他服務(wù)器的TCP連接請(qǐng)求時(shí),會(huì)交由receiveConnection函數(shù)來(lái)處理。
為了避免兩臺(tái)機(jī)器之間重復(fù)地創(chuàng)建TCP連接,Zookeeper設(shè)計(jì)一種建立TCP連接的規(guī)則:只允許SID大的服務(wù)器主動(dòng)和其他服務(wù)器建立連接,否則斷開(kāi)連接。如果當(dāng)前服務(wù)器的SID創(chuàng)建相應(yīng)的消息發(fā)送器SendWorker和消息接收器RecvWorker ,并啟動(dòng)他們。
RecvWorker只需要不斷從這個(gè)TCP連接中讀取消息,并將其保存到recvQueue隊(duì)列中。
SendWorker只需要不斷地從對(duì)應(yīng)的消息發(fā)送隊(duì)列中獲取出一個(gè)消息來(lái)發(fā)送即可,同時(shí)將這個(gè)消息放入lastMessageSent中來(lái)作為最近發(fā)送過(guò)的消息。如果當(dāng)前遠(yuǎn)程服務(wù)器的消息發(fā)送隊(duì)列為空,那么這個(gè)時(shí)候就需要從lastMessageSent中取出一個(gè)最近發(fā)送過(guò)的消息來(lái)進(jìn)行再次發(fā)送。這個(gè)細(xì)節(jié)的處理主要是為了解決這樣一類(lèi)的分布式問(wèn)題:接受方在消息接受前,或者是在接收到消息后服務(wù)器掛掉了,導(dǎo)致消息尚未被正確處理。那么如此重復(fù)發(fā)送是否會(huì)導(dǎo)致其他問(wèn)題呢?當(dāng)然,這里可以放心的一點(diǎn)是,Zookeeper能夠保證接收方在處理消息的時(shí)候,會(huì)對(duì)重復(fù)消息進(jìn)行正確的處理。
