zookeeper當配置爲羣集模式,在啓動或異常狀況將被選舉爲的例子Leader。默認選擇算法FastLeaderElection
。java
不知道zookeeper夠考慮這樣一個問題:某個服務可以配置爲多個實例共同構成一個集羣對外提供服務。其每一個實例本地都存有冗餘數據,每一個實例都可以直接對外提供讀寫服務。在這個集羣中爲了保證數據的一致性,需要有一個Leader來協調一些事務。那麼問題來了:怎樣肯定哪個實例是Leader呢?算法
問題的難點在於:分佈式
- 沒有一個仲裁者來選定Leader
- 每一個實例本地可能已經存在數據,不肯定哪一個實例上的數據是最新的
分佈式選舉算法正是用來解決問題的。post
本文基於zookeeper 3.4.6 的源代碼進行分析。FastLeaderElection算法的源代碼全部位於FastLeaderElection.java
文件裏,其對外接口爲FastLeaderElection.lookForLeader
,該接口是一個同步接口,直到選舉結束纔會返回。相同由於網上已有相似文章,因此我就從圖示的角度來闡述。閱讀一些其它文章有利於得到初步印象:.net
- 深刻淺出Zookeeper之五 Leader選舉。代碼導讀
- zookeeper3.3.3源代碼分析(二)FastLeader選舉算法。文字描寫敘述較細
主要流程
閱讀代碼和以上推薦文章可以把整個流程梳理清楚。線程
實現上,包含了一個消息處理主循環,也是選舉的主要邏輯。以及一個消息發送隊列處理線程和消息解碼線程。主要流程可歸納爲下圖:code
推薦對比着推薦的文章及代碼理解。不贅述。blog
咱們從感性上來理解這個算法。接口
每一個節點,至關於一個選民,他們都有本身的推薦人,最開始他們都推薦本身。隊列
誰更適合成爲Leader有一個簡單的規則,好比sid夠大(配置)、持有的數據夠新(zxid夠大)。
每一個選民都告訴其它選民本身眼下的推薦人是誰。相似於出去搞宣傳拉攏其它選民。每一個選民發現有比本身更適合的人時就轉而推薦這個更適合的人。最後。大部分人意見一致時,就可以結束選舉。
就這麼簡單。
總體上有一種不斷演化逼近結果的感受。
固然。會有些特殊狀況的處理。
好比總共3個選民,1和2已經肯定3是Leader,但3還不知情,此時就走入LEADING/FOLLOWING
的分支,選民3僅僅是接收結果。
代碼中不是所有邏輯都在這個大流程中完畢的。
在接收消息線程中。還可能單獨地迴應某個節點(WorkerReceiver.run
):
從這裏可以看出。當某個節點已經肯定選舉結果再也不處於LOOKING
狀態時。其收到LOOKING
消息時都會直接回應選舉的終於結果。結合上面那個例如。至關於某次選舉結束了,這個時候來了選民4又發起一次新的選舉,那麼其它選民就直接告訴它當前的Leader狀況。至關於,在這個集羣主從已經就緒的狀況下,又開啓了一個實例,這個實例就會直接使用當前的選舉結果。
狀態轉換
每個節點上有一些重要的做用結構:
- 當前推薦人。初始推薦本身。每次收到其它更好的推薦人時就更新
- 其它人的投票集合。用於肯定什麼時候選舉結束
每次推薦人更新時就會進行廣播,正是這個不斷地廣播驅動整個算法趨向於結果。
若是有3個節點A/B/C,其都尚未數據,依照sid關係爲C>B>A,那麼依照規則。C更可能成爲Leader,其各個節點的狀態轉換爲:
圖中。v(A)表示當前推薦人爲A。r[]表示收到的投票集合。
可以看看當其它節點已經肯定投票結果時,即再也不是LOOKING
時的狀態:
代碼中有一個特殊的投票集合outofelection
,我理解爲選舉已結束的那些投票,這些投票僅用於表徵選舉結果。
當一個新啓動的節點增長集羣時。它對集羣內其它節點發出投票請求。而其它節點已不處於LOOKING
狀態,此時其它節點回應選舉結果。該節點收集這些結果到outofelection
中,終於在收到合法LEADER消息且這些選票也構成選舉結束條件時,該節點就結束本身的選舉行爲。注意到代碼中會logicalclock = n.electionEpoch;
更新選舉輪數
完