分布式开发必须了解的Zookeeper的Leader选举机制(源码解析)
分布式開發(fā)必須知道的Zookeeper知識及其的Leader選舉機制(ZAB原子廣播協(xié)議)
??ZooKeeper是Hadoop下的一個子項目,它是一個針對大型分布式系統(tǒng)的可靠協(xié)調(diào)系統(tǒng),提供的功能包括:配置維護、名字服務(wù)、分布式同步、組服務(wù)等; 它的目標(biāo)就是封裝好復(fù)雜易出錯的關(guān)鍵服務(wù),將簡單易用的接口和性能高效、功能穩(wěn)定的系統(tǒng)提供給用戶。
ZooKeeper系統(tǒng)架構(gòu)
??下圖就是Zookeeper的架構(gòu)圖:
??從上面的架構(gòu)圖中,我們需要了解的主要的信息有:
??①ZooKeeper分為服務(wù)器端(Server)和客戶端(Client),客戶端可以連接到整個ZooKeeper服務(wù)的任意服務(wù)器上(Leader除外)。
??②ZooKeeper 啟動時,將從實例中選舉一個Leader,Leader 負責(zé)處理數(shù)據(jù)更新等操作,一個更新操作成功的標(biāo)志是當(dāng)且僅當(dāng)大多數(shù)Server在內(nèi)存中成功修改數(shù)據(jù)(Quorom機制)。每個Server 在內(nèi)存中存儲了一份數(shù)據(jù)。
??③Zookeeper是可以集群復(fù)制的,集群間通過Zab協(xié)議(Zookeeper Atomic Broadcast)來保持?jǐn)?shù)據(jù)的一致性;
??④Zab協(xié)議包含兩個階段:Leader Election階段和Atomic Brodcast階段。群中將選舉出一個Leader,其他的機器則稱為Follower,所有的寫操作都被傳送給Leader,并通過Brodcast將所有的更新告訴給Follower。 當(dāng)Leader被選舉出來,且大多數(shù)服務(wù)器完成了和leader的狀態(tài)同步后,Leadder Election 的過程就結(jié)束了,就將會進入到Atomic Brodcast的過程。Atomic Brodcast同步Leader和Follower之間的信息,保證Leader和Follower具有形同的系統(tǒng)狀態(tài)。
Quorom機制簡介
??在分布式系統(tǒng)中,冗余數(shù)據(jù)是保證可靠性的手段,因此冗余數(shù)據(jù)的一致性維護就非常重要。一般而言,一個寫操作必須要對所有的冗余數(shù)據(jù)都更新完成了,才能稱為成功結(jié)束。比如一份數(shù)據(jù)在5臺設(shè)備上有冗余,因為不知道讀數(shù)據(jù)會落在哪一臺設(shè)備上,那么一次寫操作,必須5臺設(shè)備都更新完成,寫操作才能返回。
??對于寫操作比較頻繁的系統(tǒng),這個操作的瓶頸非常大。Quorum算法可以讓寫操作只要寫完3臺就返回。剩下的由系統(tǒng)內(nèi)部緩慢同步完成。而讀操作,則需要也至少讀3臺,才能保證至少可以讀到一個最新的數(shù)據(jù)。
Zookeeper中的四種角色
①Leader:領(lǐng)導(dǎo)者,負責(zé)進行投票的發(fā)起和決議,更新系統(tǒng)狀態(tài)。
②Learner:學(xué)習(xí)者
③Follower(Learner的子類):跟隨者,用于接受客戶端請求并向客戶端返回結(jié)結(jié)果,在選主過程中參與投票,Follower可以接收Client請求,如果是寫請求將轉(zhuǎn)發(fā)給Leader來更新系統(tǒng)狀態(tài)。
④Observer:觀察者,可以接收客戶端連接,將寫請求轉(zhuǎn)發(fā)給Leader節(jié)點,但是不參與投票過程,只是同步Leader狀態(tài),因為Follower增多會導(dǎo)致投票階段延遲增大,影響性能。Observer的目的是為了擴展系統(tǒng),提高讀取數(shù)據(jù)。
為什么Zookeeper中的Server數(shù)目一般為基數(shù)?
??我們知道在Zookeeper中 Leader 選舉算法采用了Quorom算法。該算法的核心思想是當(dāng)多數(shù)Server寫成功,則任務(wù)數(shù)據(jù)寫成功。假設(shè)有3個Server,則最多允許一個Server掛掉;如果有4個Server,則同樣最多允許一個Server掛掉。既然3個或者4個Server,同樣最多允許1個Server掛掉,那么它們的可靠性是一樣的,所以選擇奇數(shù)個ZooKeeper Server即可,這里選擇3個Server。
Zookeeper用于Leader選舉的算法
①基于UDP的LeaderElection
②基于UDP的FastLeaderElection
③基于UDP和認(rèn)證的FastLeaderElection
④基于TCP的FastLeaderElection(默認(rèn)值)
FastLeaderElection機制
??接下來要說的就是Zookeeper的Leader選舉機制核心算法FastLeaderElection類。FastLeaderElection實現(xiàn)了Election接口,其需要實現(xiàn)接口中定義的lookForLeader(核心的選舉算法入口)方法和shutdown方法FastLeaderElection選舉算法是標(biāo)準(zhǔn)的Fast Paxos算法實現(xiàn),可解決LeaderElection選舉算法收斂速度慢的問題。
術(shù)語介紹
sid(myid)
??每個Zookeeper服務(wù)器,都需要在數(shù)據(jù)文件夾下創(chuàng)建一個名為myid的文件,該文件包含整個Zookeeper集群唯一的ID(整數(shù))。例如某Zookeeper集群包含三臺服務(wù)器,hostname分別為zoo1、zoo2和zoo3,其myid分別為1、2和3,則在配置文件中其ID與hostname必須一一對應(yīng),如下所示。在該配置文件中,server.后面的數(shù)據(jù)即為myid(Leader選舉時用的sid或者leader)。
server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888 復(fù)制代碼zxid
??類似于RDBMS中的事務(wù)ID,用于標(biāo)識一次更新操作的Proposal ID。為了保證順序性,該zkid必須單調(diào)遞增。因此Zookeeper使用一個64位的數(shù)來表示,高32位是Leader的epoch,從1開始,每次選出新的Leader,epoch加一。低32位為該epoch內(nèi)的序號,每次epoch變化,都將低32位的序號重置。這樣保證了zxid的全局遞增性。
Zookeeper節(jié)點的四種狀態(tài)
??截圖為Zookeeper定義的四種服務(wù)器節(jié)點狀態(tài):
-
①LOOKING: 不確定Leader狀態(tài)。該狀態(tài)下的服務(wù)器認(rèn)為當(dāng)前集群中沒有Leader,會發(fā)起Leader選舉。
-
②FOLLOWING: 跟隨者狀態(tài)。表明當(dāng)前服務(wù)器角色是Follower,并且它知道Leader是誰。
-
③LEADING: 領(lǐng)導(dǎo)者狀態(tài)。表明當(dāng)前服務(wù)器角色是Leader,它會維護與Follower間的心跳。
-
④OBSERVING: 觀察者狀態(tài)。表明當(dāng)前服務(wù)器角色是Observer,與Folower唯一的不同在于不參與選舉,也不參與集群寫操作時的投票。
FastLeaderElection內(nèi)部類
FastLeaderElection的內(nèi)部類的情況如下圖:
- **Notification:**表示收到的選舉投票信息(其他服務(wù)器發(fā)來的選舉投票信息),其包含了被選舉者的id、zxid、選舉周期等信息。
- **ToSend:**表示發(fā)送給其他服務(wù)器的選舉投票信息(其他服務(wù)器發(fā)來的選舉投票信息),其包含了被選舉者的id、zxid、選舉周期等信息。
- Messenger:包含了WorkerReceiver和WorkerSender兩個內(nèi)部類。WorkerReceiver實現(xiàn)了Runnable接口,是選票接收器。WorkerSender也實現(xiàn)了Runnable接口,為選票發(fā)送器。
Notification(收到的投票信息)
- **leader:**被推選的leader的id。
- **zxid:**被推選的leader的事務(wù)id。
- **electionEpoch:**推選者的選舉周期。
- **state:**推選者的狀態(tài)。
- **sid:**推選者的id。
- **peerEpoch:**被推選者的選舉周期。
ToSend(發(fā)送的投票信息)
- **leader:**被推選的leader的id。
- **zxid:**被推選的leader的事務(wù)id。
- **electionEpoch:**推選者的選舉周期。
- **state:**推選者的狀態(tài)。
- **sid:**推選者的id。
- **peerEpoch:**被推選者的選舉周期。
WorkerSender(選票發(fā)送器)
??WorkerSender也實現(xiàn)了Runnable接口,為選票發(fā)送器,其會不斷地從sendqueue中獲取待發(fā)送的選票,并將其傳遞到底層QuorumCnxManager中。
- 獲取選票
- 發(fā)送選票
WorkerReceiver(選票接收器)
??WorkerReceiver實現(xiàn)了Runnable接口,是選票接收器。其會不斷地從QuorumCnxManager中獲取其他服務(wù)器發(fā)來的選舉消息中。先會從QuorumCnxManager中的pollRecvQueue隊列中取出其他服務(wù)器發(fā)來的選舉消息,消息封裝在Message數(shù)據(jù)結(jié)構(gòu)中。然后判斷消息中的服務(wù)器id是否包含在可以投票的服務(wù)器集合中,若不是,則會將本服務(wù)器的內(nèi)部投票發(fā)送給該服務(wù)器,其流程如下:
??若包含該服務(wù)器,則根據(jù)消息(Message)解析出投票服務(wù)器的投票信息并將其封裝為Notification,然后判斷當(dāng)前服務(wù)器是否為LOOKING,若為LOOKING,則直接將Notification放入FastLeaderElection的recvqueue。然后判斷投票服務(wù)器是否為LOOKING狀態(tài),并且其選舉周期小于當(dāng)前服務(wù)器的邏輯時鐘,則將本(當(dāng)前)服務(wù)器的內(nèi)部投票發(fā)送給該服務(wù)器,否則,直接忽略掉該投票。其流程如下:
??若本服務(wù)器的狀態(tài)不為LOOKING,則會根據(jù)投票服務(wù)器中解析的version信息來構(gòu)造ToSend消息,放入sendqueue,等待發(fā)送,起流程如下:
核心函數(shù)分析
sendNotifications函數(shù)
??其會遍歷所有的參與者投票集合,然后將自己的選票信息發(fā)送至上述所有的投票者集合,其并非同步發(fā)送,而是將ToSend消息放置于sendqueue中,之后由WorkerSender進行發(fā)送。
totalOrderPredicate函數(shù)
??該函數(shù)將接收的投票與自身投票進行PK,查看是否消息中包含的服務(wù)器id是否更優(yōu),其按照epoch、zxid、id的優(yōu)先級進行PK。
- 判斷消息里的epoch是不是比當(dāng)前的大,如果大則消息中id對應(yīng)的服務(wù)器就是leader。
- 如果epoch相等則判斷zxid,如果消息里的zxid大,則消息中id對應(yīng)的服務(wù)器就是leader。
- 如果前面兩個都相等那就比較服務(wù)器id,如果大,則其就是leader。
termPredicate函數(shù)
??該函數(shù)用于判斷Leader選舉是否結(jié)束,即是否有一半以上的服務(wù)器選出了相同的Leader,其過程是將收到的選票與當(dāng)前選票進行對比,選票相同的放入同一個集合,之后判斷選票相同的集合是否超過了半數(shù)。
checkLeader函數(shù)
??該函數(shù)檢查是否已經(jīng)完成了Leader的選舉,此時Leader的狀態(tài)應(yīng)該是LEADING狀態(tài)。
lookForLeader函數(shù)
??該函數(shù)就是leader選舉的核心方法,代碼行數(shù)有點多,這里僅分析其中的一部分。
- 更新邏輯時鐘、更新選票、發(fā)送選票
- 獲取投票數(shù)據(jù)、連接服務(wù)器
- 選舉Leader
- LEADING狀態(tài)處理
??以上就是關(guān)于zookeeper的所有基本知識與Leader選舉機制的講解。喜歡的話記得轉(zhuǎn)發(fā)額。
??歡迎大家關(guān)注我的微信公眾號,不定期分享各類面試題、踩坑記錄、高階知識分享。
轉(zhuǎn)載于:https://juejin.im/post/5d00c019e51d4577770e7370
總結(jié)
以上是生活随笔為你收集整理的分布式开发必须了解的Zookeeper的Leader选举机制(源码解析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 讨论一下文章的阅读量 (个人观点)
- 下一篇: Python学习笔记之六:在VS中调用P