Zookeeper之Leader选举源码分析
Zookeeper源碼下載地址:https://github.com/apache/zookeeper
1.選舉流程
Zookeeeper的Leader選舉會分兩個過程。
服務啟動時的leader選舉
每個節(jié)點啟動的時候狀態(tài)都是LOOKING,處于觀望狀態(tài),接下來就開始進行選leader流程。
進行l(wèi)eader選舉,至少需要兩臺機器,我們選取3臺機器組成的服務器集群為例。在集群初始化階段,當有一臺服務器server1啟動時,它本身是無法進行和完成leader選舉的,當第二臺服務器server2啟動時,這個時候兩臺機器可以相互通信,每臺機器都試圖找到leader,于是進入leader選舉過程。過程如下:
(1)每個server發(fā)出一個投票。由于是初始情況,server1和server2都會將自己作為leader服務器來進行投票,每次投票會包含所推舉的服務器的mid、ZXID和epoch,使用(myid,ZXID,epoch)來表示。此時server1的投票為(1,0),server2的投票為(2,0),然后各自將這個投票發(fā)給集群中其它機器。
(2)接受來自各個服務器的投票。集群的每個服務器收到投票后,首先判斷該投票的有效性,如檢查是否是本輪投票(epoch)、是否來自LOOKING狀態(tài)的服務器。
(3)處理投票。針對每一個投票,服務器都需要將別人的投票和自己的投票進行PK,PK規(guī)則如下:
-
優(yōu)先檢查ZXID。ZXID比較大的服務器優(yōu)先作為leader
-
如果ZXID相同,那么就比較myid。myid較大的服務器作為leader服務器
對于server1而言,它的投票是(1,0),接收server2的投票為(2,0),首先會比較兩者的ZXID,均為0,再比較myid,此時server2的myid最大,于是更新自己的投票為(2,0),然后重新投票,對于server2而言,它不需要更新自己的投票,只是再次向集群中所有機器發(fā)出上一次投票信息即可。
(4)統(tǒng)計投票。每次投票后,服務器都會統(tǒng)計投票信息,判斷是否已經有過半機器接收到相同的投票信息,對于server1、server2而言,都統(tǒng)計出集群中已經有兩臺機器接受了(2,0)的投票信息,此時便認為已經選出了leader。
(5)改變服務器狀態(tài)。一旦確定了leader,每個服務器就會更新自己的狀態(tài),如果是follower,那么就變更為FOLLOWING,如果是leader,就變更為LEADING。
運行過程中的leader選舉
當集群中的 leader 服務器出現宕機或者不可用的情況時,那么整個集群將無法對外提供服務,而是進入新一輪的leader 選舉,服務器運行期間的 leader 選舉和啟動時期的 leader 選舉基本過程是一致的。
(1)變更狀態(tài)。leader宕機后,剩下的非observer服務器都會將自己的服務器狀態(tài)變更為LOOKING,然后開始進入leader選舉過程。
(2)每個server會發(fā)出一個投票。在運行期間,每個服務器上的ZXID可能不同,此時假定server1的ZXID為123,server3的ZXID為122;在第一輪投票中,server1和server3都會投給自己,產生投票(1,123),(3,122),然后各自將投票發(fā)送給集群中所有機器。接收來自各個服務器的投票。
(3)處理投票。與啟動時選舉過程相同。此時server1因為ZXID高于server3,server1將會被推舉為leader
(4)統(tǒng)計投票。與啟動時過程相同。
(5)改變服務器的狀態(tài)。與啟動時過程相同。
2.源碼分析
?
初始化并啟動:
這里會判斷zookeeper是單機模式還是集群模式,如果是集群模式,就會進入對應的選舉代碼。
?
設置各種參數。大部分配置都是在conf里面的配置文件中配置。
啟動主線程。QuorumPeer重寫了Thread.start方法。
調用quorumpeer的start方法
loadDataBase,主要是從本地文件中恢復數據以及獲取最新的zxid
初始化leaderElection
配置選舉算法,選舉算法有3種,可以通過zoo.cfg進行配置,默認是fast選舉
繼續(xù)看FastLeaderElection的初始化動作。主要初始化了業(yè)務層的發(fā)送隊列和接收隊列
?
接下來看fle.start()。主要是對發(fā)送線程和接收線程的初始化。
?
wsThread和wrThread的初始化動作在FastLeaderElection 的 starter 方法里面進行,這里面有兩個內部類,一個是 WorkerSender,一個是 WorkerReceiver,負責發(fā)送投票信息和接收投票信息
然后再回到QuorumPeer類。初始化完成,調用super.start()方法,即運行QuorumPeer的run方法
前面的部分主要是做JMX監(jiān)控注冊
重要的部分在while循環(huán)中
調用setCurrentVote(makeLEStrategy().lookForLeader())。根據策略決定FastLeaderElection中的選舉算法。
LOOKFORLEADER開始選舉
?
?
?
消息如何廣播,看sendNotifications
WorkerSender
3.FastLeaderElection 選舉過程
其實在這個投票過程中就涉及到幾個類
FastLeaderElection:FastLeaderElection 實現了 Election 接口,實現各服務器之間基于 TCP 協(xié)議進行選舉
Notification:內部類,Notification 表示收到的選舉投票信息(其他服務器發(fā)來的選舉投票信息),其包含了被選舉者的 id、zxid、選舉周期等信息
ToSend:ToSend 表示發(fā)送給其他服務器的選舉投票信息,也包含了被選舉者的 id、zxid、選舉周期等信息
Messenger: Messenger 包 含 了 WorkerReceiver 和WorkerSender 兩個內部類;
WorkerReceiver: 實現了 Runnable 接口,是選票接收器。其會不斷地從 QuorumCnxManager 中獲取其他服務器發(fā)來的選舉消息,并將其轉換成一個選票,然后保存到recvqueue 中
WorkerSender: 也實現了 Runnable 接口,為選票發(fā)送器,其會不斷地從 sendqueue 中獲取待發(fā)送的選票,并將其傳遞到底層 QuorumCnxManager 中
總結
以上是生活随笔為你收集整理的Zookeeper之Leader选举源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis的发布订阅模式以及在Sprin
- 下一篇: SpringBoot集成Redissio