ZooKeeper是Hadoop下的一個子項目,它是一個針對大型分佈式系統的可靠協調系統,提供的功能包括:配置維護、名字服務、分佈式同步、組服務等; 它的目標就是封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。面試
下圖就是Zookeeper的架構圖:算法
從上面的架構圖中,咱們須要瞭解的主要的信息有:bash
①ZooKeeper分爲服務器端(Server)和客戶端(Client),客戶端能夠鏈接到整個ZooKeeper服務的任意服務器上(Leader除外)。服務器
②ZooKeeper 啓動時,將從實例中選舉一個Leader,Leader 負責處理數據更新等操做,一個更新操做成功的標誌是當且僅當大多數Server在內存中成功修改數據(Quorom機制)。每一個Server 在內存中存儲了一份數據。微信
③Zookeeper是能夠集羣複製的,集羣間經過Zab協議(Zookeeper Atomic Broadcast)來保持數據的一致性;數據結構
④Zab協議包含兩個階段:Leader Election階段和Atomic Brodcast階段。羣中將選舉出一個Leader,其餘的機器則稱爲Follower,全部的寫操做都被傳送給Leader,並經過Brodcast將全部的更新告訴給Follower。 當Leader被選舉出來,且大多數服務器完成了和leader的狀態同步後,Leadder Election 的過程就結束了,就將會進入到Atomic Brodcast的過程。Atomic Brodcast同步Leader和Follower之間的信息,保證Leader和Follower具備形同的系統狀態。架構
在分佈式系統中,冗餘數據是保證可靠性的手段,所以冗餘數據的一致性維護就很是重要。通常而言,一個寫操做必需要對全部的冗餘數據都更新完成了,才能稱爲成功結束。好比一份數據在5臺設備上有冗餘,由於不知道讀數據會落在哪一臺設備上,那麼一次寫操做,必須5臺設備都更新完成,寫操做才能返回。分佈式
對於寫操做比較頻繁的系統,這個操做的瓶頸很是大。Quorum算法可讓寫操做只要寫完3臺就返回。剩下的由系統內部緩慢同步完成。而讀操做,則須要也至少讀3臺,才能保證至少能夠讀到一個最新的數據。函數
①Leader:領導者,負責進行投票的發起和決議,更新系統狀態。oop
②Learner:學習者
③Follower(Learner的子類):跟隨者,用於接受客戶端請求並向客戶端返回結結果,在選主過程當中參與投票,Follower能夠接收Client請求,若是是寫請求將轉發給Leader來更新系統狀態。
④Observer:觀察者,能夠接收客戶端鏈接,將寫請求轉發給Leader節點,可是不參與投票過程,只是同步Leader狀態,由於Follower增多會致使投票階段延遲增大,影響性能。Observer的目的是爲了擴展系統,提升讀取數據。
咱們知道在Zookeeper中 Leader 選舉算法採用了Quorom算法。該算法的核心思想是當多數Server寫成功,則任務數據寫成功。假設有3個Server,則最多容許一個Server掛掉;若是有4個Server,則一樣最多容許一個Server掛掉。既然3個或者4個Server,一樣最多容許1個Server掛掉,那麼它們的可靠性是同樣的,因此選擇奇數個ZooKeeper Server便可,這裏選擇3個Server。
①基於UDP的LeaderElection
②基於UDP的FastLeaderElection
③基於UDP和認證的FastLeaderElection
④基於TCP的FastLeaderElection(默認值)
接下來要說的就是Zookeeper的Leader選舉機制核心算法FastLeaderElection類。FastLeaderElection實現了Election接口,其須要實現接口中定義的lookForLeader(核心的選舉算法入口)方法和shutdown方法FastLeaderElection選舉算法是標準的Fast Paxos算法實現,可解決LeaderElection選舉算法收斂速度慢的問題。
sid(myid)
每一個Zookeeper服務器,都須要在數據文件夾下建立一個名爲myid的文件,該文件包含整個Zookeeper集羣惟一的ID(整數)。例如某Zookeeper集羣包含三臺服務器,hostname分別爲zoo一、zoo2和zoo3,其myid分別爲一、2和3,則在配置文件中其ID與hostname必須一一對應,以下所示。在該配置文件中,server.後面的數據即爲myid(Leader選舉時用的sid或者leader)。
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
複製代碼
zxid
相似於RDBMS中的事務ID,用於標識一次更新操做的Proposal ID。爲了保證順序性,該zkid必須單調遞增。所以Zookeeper使用一個64位的數來表示,高32位是Leader的epoch,從1開始,每次選出新的Leader,epoch加一。低32位爲該epoch內的序號,每次epoch變化,都將低32位的序號重置。這樣保證了zxid的全局遞增性。
截圖爲Zookeeper定義的四種服務器節點狀態:
①LOOKING: 不肯定Leader狀態。該狀態下的服務器認爲當前集羣中沒有Leader,會發起Leader選舉。
②FOLLOWING: 跟隨者狀態。代表當前服務器角色是Follower,而且它知道Leader是誰。
③LEADING: 領導者狀態。代表當前服務器角色是Leader,它會維護與Follower間的心跳。
④OBSERVING: 觀察者狀態。代表當前服務器角色是Observer,與Folower惟一的不一樣在於不參與選舉,也不參與集羣寫操做時的投票。
FastLeaderElection的內部類的狀況以下圖:
WorkerSender也實現了Runnable接口,爲選票發送器,其會不斷地從sendqueue中獲取待發送的選票,並將其傳遞到底層QuorumCnxManager中。
WorkerReceiver實現了Runnable接口,是選票接收器。其會不斷地從QuorumCnxManager中獲取其餘服務器發來的選舉消息中。先會從QuorumCnxManager中的pollRecvQueue隊列中取出其餘服務器發來的選舉消息,消息封裝在Message數據結構中。而後判斷消息中的服務器id是否包含在能夠投票的服務器集合中,若不是,則會將本服務器的內部投票發送給該服務器,其流程以下:
若包含該服務器,則根據消息(Message)解析出投票服務器的投票信息並將其封裝爲Notification,而後判斷當前服務器是否爲LOOKING,若爲LOOKING,則直接將Notification放入FastLeaderElection的recvqueue。而後判斷投票服務器是否爲LOOKING狀態,而且其選舉週期小於當前服務器的邏輯時鐘,則將本(當前)服務器的內部投票發送給該服務器,不然,直接忽略掉該投票。其流程以下:
若本服務器的狀態不爲LOOKING,則會根據投票服務器中解析的version信息來構造ToSend消息,放入sendqueue,等待發送,起流程以下:
其會遍歷全部的參與者投票集合,而後將本身的選票信息發送至上述全部的投票者集合,其並不是同步發送,而是將ToSend消息放置於sendqueue中,以後由WorkerSender進行發送。
該函數將接收的投票與自身投票進行PK,查看是否消息中包含的服務器id是否更優,其按照epoch、zxid、id的優先級進行PK。
該函數用於判斷Leader選舉是否結束,便是否有一半以上的服務器選出了相同的Leader,其過程是將收到的選票與當前選票進行對比,選票相同的放入同一個集合,以後判斷選票相同的集合是否超過了半數。
該函數檢查是否已經完成了Leader的選舉,此時Leader的狀態應該是LEADING狀態。
該函數就是leader選舉的核心方法,代碼行數有點多,這裏僅分析其中的一部分。
以上就是關於zookeeper的全部基本知識與Leader選舉機制的講解。喜歡的話記得轉發額。
歡迎你們關注個人微信公衆號,不按期分享各種面試題、踩坑記錄、高階知識分享。