一、Leader選舉過程
Leader選舉是保證分布式數據一致性的關鍵所在。當Zookeeper集群中的一臺服務器出現以下兩種情況之一時,需要進入Leader選舉。
(1) 服務器初始化啟動。
(2) 服務器運行期間無法和Leader保持連接。
下面就兩種情況進行分析講解。
1、服務器啟動時期的Leader選舉
若進行Leader選舉,則至少需要兩臺機器,這里選取3臺機器組成的服務器集群為例。在集群初始化階段,當有一臺服務器Server1啟動時,其單獨無法進行和完成Leader選舉,當第二臺服務器Server2啟動時,此時兩臺機器可以相互通信,每臺機器都試圖找到Leader,于是進入Leader選舉過程。選舉過程如下:
(1) 每個Server發出一個投票。由于是初始情況,Server1和Server2都會將自己作為Leader服務器來進行投票,每次投票會包含所推舉的服務器的myid和ZXID,使用(myid, ZXID)來表示,此時Server1的投票為(1, 0),Server2的投票為(2, 0),然后各自將這個投票發給集群中其他機器。
(2) 接受來自各個服務器的投票。集群的每個服務器收到投票后,首先判斷該投票的有效性,如檢查是否是本輪投票、是否來自LOOKING狀態的服務器。
(3) 處理投票。針對每一個投票,服務器都需要將別人的投票和自己的投票進行PK,PK規則如下
a、優先檢查ZXID。ZXID比較大的服務器優先作為Leader。
b、如果ZXID相同,那么就比較myid。myid較大的服務器作為Leader服務器。
對于Server1而言,它的投票是(1, 0),接收Server2的投票為(2, 0),首先會比較兩者的ZXID,均為0,再比較myid,此時Server2的myid最大,于是更新自己的投票為(2, 0),然后重新投票,對于Server2而言,其無須更新自己的投票,只是再次向集群中所有機器發出上一次投票信息即可。
(4) 統計投票。每次投票后,服務器都會統計投票信息,判斷是否已經有過半機器接受到相同的投票信息,對于Server1、Server2而言,都統計出集群中已經有兩臺機器接受了(2, 0)的投票信息,此時便認為已經選出了Leader。
(5) 改變服務器狀態。一旦確定了Leader,每個服務器就會更新自己的狀態,如果是Follower,那么就變更為FOLLOWING,如果是Leader,就變更為LEADING。
2、服務器運行時期的Leader選舉
在Zookeeper運行期間,Leader與非Leader服務器各司其職,即便當有非Leader服務器宕機或新加入,此時也不會影響Leader,但是一旦Leader服務器掛了,那么整個集群將暫停對外服務,進入新一輪Leader選舉,其過程和啟動時期的Leader選舉過程基本一致。假設正在運行的有Server1、Server2、Server3三臺服務器,當前Leader是Server2,若某一時刻Leader掛了,此時便開始Leader選舉。選舉過程如下
(1) 變更狀態。Leader掛后,余下的非Observer服務器都會講自己的服務器狀態變更為LOOKING,然后開始進入Leader選舉過程。
(2) 每個Server會發出一個投票。在運行期間,每個服務器上的ZXID可能不同,此時假定Server1的ZXID為123,Server3的ZXID為122;在第一輪投票中,Server1和Server3都會投自己,產生投票(1, 123),(3, 122),然后各自將投票發送給集群中所有機器。
(3) 接收來自各個服務器的投票。與啟動時過程相同。
(4) 處理投票。與啟動時過程相同,此時,Server1將會成為Leader。
(5) 統計投票。與啟動時過程相同。
(6) 改變服務器的狀態。與啟動時過程相同。
二、Leader選舉算法分析
在3.4.0后的Zookeeper的版本只保留了TCP版本的 FastLeaderElection 選舉算法。當一臺機器進入Leader選舉時,當前集群可能會處于以下兩種狀態
a、集群中已存在Leader。
b、集群中不存在Leader。
對于集群中已經存在Leader而言,此種情況一般都是某臺機器啟動得較晚,在其啟動之前,集群已經在正常工作,對這種情況,該機器試圖去選舉Leader時,會被告知當前服務器的Leader信息,對于該機器而言,僅僅需要和Leader機器建立起連接,并進行狀態同步即可。而在集群中不存在Leader情況下則會相對復雜,其步驟如下
(1) 第一次投票。無論哪種導致進行Leader選舉,集群的所有機器都處于試圖選舉出一個Leader的狀態,即LOOKING狀態,LOOKING機器會向所有其他機器發送消息,該消息稱為投票。投票中包含了SID(服務器的唯一標識)和ZXID(事務ID),(SID, ZXID)形式來標識一次投票信息。假定Zookeeper由5臺機器組成,SID分別為1、2、3、4、5,ZXID分別為9、9、9、8、8,并且此時SID為2的機器是Leader機器,某一時刻,1、2所在機器出現故障,因此集群開始進行Leader選舉。在第一次投票時,每臺機器都會將自己作為投票對象,于是SID為3、4、5的機器投票情況分別為(3, 9),(4, 8), (5, 8)。
(2) 變更投票。每臺機器發出投票后,也會收到其他機器的投票,每臺機器會根據一定規則來處理收到的其他機器的投票,并以此來決定是否需要變更自己的投票,這個規則也是整個Leader選舉算法的核心所在,其中術語描述如下
vote_sid:接收到的投票中所推舉Leader服務器的SID。
vote_zxid:接收到的投票中所推舉Leader服務器的ZXID。
self_sid:當前服務器自己的SID。
self_zxid:當前服務器自己的ZXID。
每次對收到的投票的處理,都是對(vote_sid, vote_zxid)和(self_sid, self_zxid)對比的過程。
規則一:如果vote_zxid大于self_zxid,就認可當前收到的投票,并再次將該投票發送出去。
規則二:如果vote_zxid小于self_zxid,那么堅持自己的投票,不做任何變更。
規則三:如果vote_zxid等于self_zxid,那么就對比兩者的SID,如果vote_sid大于self_sid,那么就認可當前收到的投票,并再次將該投票發送出去。
規則四:如果vote_zxid等于self_zxid,并且vote_sid小于self_sid,那么堅持自己的投票,不做任何變更。
結合上面規則,給出下面的集群變更過程。
(3) 確定Leader。經過第二輪投票后,集群中的每臺機器都會再次接收到其他機器的投票,然后開始統計投票,如果一臺機器收到了超過半數的相同投票,那么這個投票對應的SID機器即為Leader。此時Server3將成為Leader。
由上面規則可知,通常那臺服務器上的數據越新(ZXID會越大),其成為Leader的可能性越大,也就越能夠保證數據的恢復。如果ZXID相同,則SID越大機會越大。