Zookeeper-Zookeeper leader選舉
在上一篇文章中我們大致瀏覽了zookeeper的啟動過程,並且提到在Zookeeper的啟動過程中leader選舉是非常重要而且最複雜的一個環節。那麼什麼是leader選舉呢?zookeeper為什麼需要leader選舉呢?zookeeper的leader選舉的過程又是什麼樣子的?本文的目的就是解決這三個問題。
首先我們來看看什麼是leader選舉。其實這個很好理解,leader選舉就像總統選舉一樣,每人一票,獲得多數票的人就當選為總統了。在zookeeper叢集中也是一樣,每個節點都會投票,如果某個節點獲得超過半數以上的節點的投票,則該節點就是leader節點了。
國家選舉總統是為了選一個最高統帥,治理國家。那麼zookeeper叢集選舉的目的又是什麼呢?其實這個要清楚明白的解釋還是挺複雜的。我們可以簡單點想這個問題:我們有一個zookeeper叢集,有好幾個節點。每個節點都可以接收請求,處理請求。那麼,如果這個時候分別有兩個客戶端向兩個節點發起請求,請求的內容是修改同一個資料。比如客戶端c1,請求節點n1,請求是set a = 1; 而客戶端c2,請求節點n2,請求內容是set a = 2;
那麼最後a是等於1還是等於2呢? 這在一個分散式環境裡是很難確定的。解決這個問題有很多辦法,而zookeeper的辦法是,我們選一個總統出來,所有的這類決策都提交給總統一個人決策,那之前的問題不就沒有了麼。
那我們現在的問題就是怎麼來選擇這個總統呢? 在現實中,選擇總統是需要宣講拉選票的,那麼在zookeeper的世界裡這又如何處理呢?我們還是show code吧。
在QuorumPeer的startLeaderElection方法裡包含leader選舉的邏輯。Zookeeper預設提供了4種選舉方式,預設是第4種: FastLeaderElection。
我們先假設我們這是一個嶄新的叢集,嶄新的叢集的選舉和之前執行過一段時間的選舉是有稍許不同的,後面會提及。
節點狀態: 每個叢集中的節點都有一個狀態 LOOKING, FOLLOWING, LEADING, OBSERVING。都屬於這4種,每個節點啟動的時候都是LOOKING狀態,如果這個節點參與選舉但最後不是leader,則狀態是FOLLOWING,如果不參與選舉則是OBSERVING,leader的狀態是LEADING。
開始這個選舉演算法前,每個節點都會在zoo.cfg上指定的監聽埠啟動監聽(server.1=127.0.0.1:20881:20882),這裡的20882就是這裡用於選舉的埠。
在FastLeaderElection裡有一個Manager的內部類,這個類裡有啟動了兩個執行緒:WorkerReceiver, WorkerSender。為什麼說選舉這部分複雜呢,我覺得就是這些執行緒就像左右互搏一樣,非常難以理解。顧名思義,這兩個執行緒一個是處理從別的節點接收訊息的,一個是向外傳送訊息的。對於外面的邏輯接收和傳送的邏輯都是非同步的。
這裡配置好了,QuorumPeer的run方法就開始執行了,這裡實現的是一個簡單的狀態機。因為現在是LOOKING狀態,所以進入LOOKING的分支,呼叫選舉演算法開始選舉了:
setCurrentVote(makeLEStrategy().lookForLeader());
而在lookForLeader裡主要是幹什麼呢?首先我們會更新一下一個叫邏輯時鐘的東西,這也是在分散式演算法裡很重要的一個概念,但是在這裡先不介紹,可以參考後面的論文。然後決定我要投票給誰。不過zookeeper這裡的選舉真直白,每個節點都選自己(汗),選我,選我,選我...... 然後向其他節點廣播這個選舉資訊。這裡實際上並沒有真正的傳送出去,只是將選舉資訊放到由WorkerSender管理的一個佇列裡。
synchronized(this){ //邏輯時鐘 logicalclock++; //getInitLastLoggedZxid(), getPeerEpoch()這裡先不關心是什麼,後面會討論 updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch()); } //getInitId() 即是獲取選誰,id就是myid裡指定的那個數字,所以說一定要唯一 private long getInitId(){ if(self.getQuorumVerifier().getVotingMembers().containsKey(self.getId())) return self.getId(); else return Long.MIN_VALUE; } //傳送選舉資訊,非同步傳送 sendNotifications();
現在我們去看看怎麼把投票資訊投遞出去。這個邏輯在WorkerSender裡,WorkerSender從sendqueue裡取出投票,然後交給QuorumCnxManager傳送。因為前面傳送投票資訊的時候是向叢集所有節點發送,所以當然也包括自己這個節點,所以QuorumCnxManager的傳送邏輯裡會判斷,如果這個要傳送的投票資訊是傳送給自己的,則不傳送了,直接進入接收佇列。
public void toSend(Long sid, ByteBuffer b) { if (self.getId() == sid) { b.position(0); addToRecvQueue(new Message(b.duplicate(), sid)); } else { //傳送給別的節點,判斷之前是不是傳送過 if (!queueSendMap.containsKey(sid)) { //這個SEND_CAPACITY的大小是1,所以如果之前已經有一個還在等待發送,則會把之前的一個刪除掉,傳送新的 ArrayBlockingQueue<ByteBuffer> bq = new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY); queueSendMap.put(sid, bq); addToSendQueue(bq, b); } else { ArrayBlockingQueue<ByteBuffer> bq = queueSendMap.get(sid); if(bq != null){ addToSendQueue(bq, b); } else { LOG.error("No queue for server " + sid); } } //這裡是真正的傳送邏輯了 connectOne(sid); } }
connectOne就是真正傳送了。在傳送之前會先把自己的id和選舉地址傳送過去。然後判斷要傳送節點的id是不是比自己的id大,如果大則不傳送了。如果要傳送又是啟動兩個執行緒:SendWorker,RecvWorker(這種一個程序內許多不同種類的執行緒,各自幹活的狀態真的很難理解)。傳送邏輯還算簡單,就是從剛才放到那個queueSendMap裡取出,然後傳送。並且傳送的時候將傳送出去的東西放到一個lastMessageSent的map裡,如果queueSendMap裡是空的,就傳送lastMessageSent裡的東西,確保對方一定收到了。
看完了SendWorker的邏輯,再來看看資料接收的邏輯吧。還記得前面提到的有個Listener在選舉埠上啟動了監聽麼,現在這裡應該接收到資料了。我們可以看到receiveConnection方法。在這裡,如果接收到的的資訊裡的id比自身的id小,則斷開連線,並嘗試傳送訊息給這個id對應的節點(當然,如果已經有SendWorker在往這個節點發送資料,則不用了)。
如果接收到的訊息的id比當前的大,則會有RecvWorker接收資料,RecvWorker會將接收到的資料放到recvQueue裡。
而FastLeaderElection的WorkerReceiver執行緒裡會不斷地從這個recvQueue裡讀取Message處理。在WorkerReceiver會處理一些協議上的事情,比如訊息格式等。除此之外還會看看接收到的訊息是不是來自投票成員。如果是投票成員,則會看看這個訊息裡的狀態,如果是LOOKING狀態並且當前的邏輯時鐘比投票訊息裡的邏輯時鐘要高,則會發個通知過去,告訴誰是leader。在這裡,剛剛啟動的嶄新叢集,所以邏輯時鐘基本上都是相同的,所以這裡還沒判斷出誰是leader。不過在這裡我們注意到如果當前節點的狀態是LOOKING的話,接收邏輯會將接收到的訊息放到FastLeaderElection的recvqueue裡。而在FastLeaderElection會從這個recvqueue裡讀取東西。
這裡就是選舉的主要邏輯了:totalOrderPredicate
protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) {return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) && ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId))))); }
1. 判斷訊息裡的epoch是不是比當前的大,如果大則訊息裡id對應的server我就承認它是leader
2. 如果epoch相等則判斷zxid,如果訊息裡的zxid比我的大我就承認它是leader
3. 如果前面兩個都相等那就比較一下server id吧,如果比我的大我就承認它是leader。
關於前面兩個東西暫時我們不去關心它,對於新啟動的叢集這兩者都是相等的。
那這樣看來server id的大小也是leader選舉的一環啊(有的人生下來註定就不平凡,這都是命啊)。
最後我們來看看,很多文章所介紹的,如果超過一半的人說它是leader,那它就是leader的邏輯吧
private boolean termPredicate( HashMap<Long, Vote> votes, Vote vote) { HashSet<Long> set = new HashSet<Long>(); //遍歷已經收到的投票集合,將等於當前投票的集合取出放到set中 for (Map.Entry<Long,Vote> entry : votes.entrySet()) { if (self.getQuorumVerifier().getVotingMembers().containsKey(entry.getKey()) && vote.equals(entry.getValue())){ set.add(entry.getKey()); } } //統計set,也就是投某個id的票數是否超過一半 return self.getQuorumVerifier().containsQuorum(set); } public boolean containsQuorum(Set<Long> ackSet) { return (ackSet.size() > half); }
最後一關:如果選的是自己,則將自己的狀態更新為LEADING,否則根據type,要麼是FOLLOWING,要麼是OBSERVING。
到這裡選舉就結束了。
這裡介紹的是一個新叢集啟動時候的選舉過程,啟動的時候就是根據zoo.cfg裡的配置,向各個節點廣播投票,一般都是選投自己。然後收到投票後就會進行進行判斷。如果某個節點收到的投票數超過一半,那麼它就是leader了。
瞭解了這個過程,我們來看看另外一個問題:
一個叢集有3臺機器,掛了一臺後的影響是什麼?掛了兩臺呢?
掛了一臺:掛了一臺後就是收不到其中一臺的投票,但是有兩臺可以參與投票,按照上面的邏輯,它們開始都投給自己,後來按照選舉的原則,兩個人都投票給其中一個,那麼就有一個節點獲得的票等於2,2 > (3/2)=1 的,超過了半數,這個時候是能選出leader的。
掛了兩臺: 掛了兩臺後,怎麼弄也只能獲得一張票, 1 不大於 (3/2)=1的,這樣就無法選出一個leader了。
在前面介紹時,為了簡單我假設的是這是一個嶄新的剛啟動的叢集,這樣的叢集與工作一段時間後的叢集有什麼不同呢?不同的就是epoch和zxid這兩個引數。在新啟動的叢集裡這兩個一般是相等的,而工作一段時間後這兩個引數有可能有的節點落後其他節點,至於是為什麼,這個還要在後面的儲存和處理額胡斷請求的文章裡介紹。
* 關於邏輯時鐘,我們的分散式大牛Leslie Lamport曾寫過一篇論文:Time, Clocks, and the Ordering of Events in a Distributed System
相關推薦
【分散式】Zookeeper的Leader選舉-選舉過程介紹
【分散式】Zookeeper的Leader選舉-選舉過程介紹 選舉開始,伺服器會各自為自己投票,在投票完成後,會將投票資訊傳送給叢集中的所有伺服器(觀察者伺服器不參與選舉)。 選票由兩部分組成:伺服器唯一標識myid和事務編號zxid,即(myid,xzid)。 zxid越大說明資料越新,在選擇演算法中
ZooKeeper之Leader選舉
Leader選舉是ZooKeeper中最重要的技術之一,也是保證分散式資料一致性的關鍵所在。 1.leader選舉 Leader選舉主要分為伺服器啟動時期的Leader選舉和伺服器執行期間的Leader選舉。以下是兩種情況的選舉大致步驟。
【Zookeeper】Leader選舉機制示例
本文介紹下zookeeper中leader選舉機制的基本用法和關鍵知識點。 一、 選項設定 提到Leader選舉,先需要重點介紹下建立znode時的Flag選項。 ZOO_EPHEMERAL ZOO_EPHEMERAL,用來標記當建立這個znode的節點和Zookeepe
Zookeeper之Leader選舉過程
Leader在叢集中是一個非常重要的角色,負責了整個事務的處理和排程,保證分散式資料一致性的關鍵所在。既然Leader在ZooKeeper叢集中這麼重要所以一定要保證叢集在任何時候都有且僅有一個Leader存在。 概念 Zookeeper Server三種角色:Leader,Follower,Observer
zookeeper curator學習(配合spring boot模擬leader選舉)
round 一段時間 .cn cti -s col tid void sco 基礎知識:http://www.cnblogs.com/LiZhiW/p/4930486.html 項目路徑:https://gitee.com/zhangjunqing/spring-boo
Zookeeper詳解(七):Zookeeper集群啟動過程和Leader選舉
文件 信息 accep upm ron factory 通信 pan actor Zookeeper集群啟動過程預啟動統一由QuorumPeerMain作為啟動類讀取zoo.cfg配置文件創建並啟動歷史文件清理器DatadirCleanupManager判斷當前是集群模式還
Zookeeper 原始碼(五)Leader 選舉
Zookeeper 原始碼(五)Leader 選舉 前面學習了 Zookeeper 服務端的相關細節,其中對於叢集啟動而言,很重要的一部分就是 Leader 選舉,接著就開始深入學習 Leader 選舉。 一、選舉規則 Leader 選舉是保證分散式資料一致性的關鍵所在。當 Zookeeper 叢集中的
Zookeeper leader選舉
讓我們分析如何在ZooKeeper集合中選舉leader節點。考慮一個叢集中有N個節點。leader選舉的過程如下: 所有節點建立具有相同路徑 /app/leader_election/guid_ 的順序、臨時節點。 ZooKeeper集合將附加10位序列號到路徑,建
zookeeper的原理和使用(二)-leader選舉
一、前言 前面學習了Zookeeper服務端的相關細節,其中對於叢集啟動而言,很重要的一部分就是Leader選舉,接著就開始深入學習Leader選舉。 二、Leader選舉 2.1 Leader選舉概述 Leader選舉是保證分散式資料一致性的關鍵所在。當Zookeepe
zookeeper leader 選舉演算法
http://www.cnblogs.com/leesf456/p/6107600.html 一、前言 前面學習了Zookeeper服務端的相關細節,其中對於叢集啟動而言,很重要的一部分就是Leader選舉,接著就開始深入學習Leader選舉。 二、Leader選舉
zookeeper二之Leader選舉
轉載:https://blog.csdn.net/u010670689/article/details/78054945 竊以為,對於zookeeper這種東西,僅僅知道怎麼安裝是遠遠不夠的(廢話麼這不是,,,),至少要對其幾個典型的應用場景進行了解,才能比較全面的知道zk究竟能幹啥,怎麼玩兒,
Zookeeper學習總結(中)——Leader選舉
“深入一點,會更快樂。” ——題記 Leader選舉是ZooKeeper最重要的技術之一,也是保證分散式資料一致性的關鍵所在。 1 預備知識 1.1 術語解釋 SID:伺服器ID,唯一標識一臺zk中的伺服器,和myid的值一致。 ZXID:事務ID,標識伺服器狀態
跟著例項學習ZooKeeper的用法: Leader選舉
ZooKeeper官方給出了使用zookeeper的幾種用途。 Leader Election Barriers Queues Locks Two-phased Commit 其它應用如Name Service, Configuration, Group Membership 在實際使用
zookeeper 中master選舉與leader選舉
開始學zookeeper 中,master選舉於leader 選舉2個概念比較模糊,談下自己的理解,如有不對地方請指出共同進步。 1.master選舉原理 有多個master,每次只能有一個master負責主要的工作,其他的master作為備份,同時對負責工作的maste
Zookeeper-Zookeeper leader選舉
在上一篇文章中我們大致瀏覽了zookeeper的啟動過程,並且提到在Zookeeper的啟動過程中leader選舉是非常重要而且最複雜的一個環節。那麼什麼是leader選舉呢?zookeeper為什麼需要leader選舉呢?zookeeper的leader選舉的過程又是什麼樣子的?本文的目的就是解決這三個問題
zookeeper leader選舉機制
最近看了下zookeeper的原始碼,先整理下leader選舉機制 先看幾個關鍵資料結構和函式 服務可能處於的狀態,從名字應該很好理解 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING; } 選票引數,還有Notifi
【ZooKeeper Notes 23】Leader選舉-來自郵件列表
logical clocks是用來唯一標識一輪Leader選舉的。 - 次Leader掛了之後,叢集中的其他機器都會對logical clocks值做自增操作。 - 新一輪的Leader選舉開始或新一輪的投票開始了的時候,會對logical clocks值做自增操作。 在
ZooKeeper使用場景-Leader選舉
Leader選舉又稱為master選舉是zookeeper中最為經典的應用場景了。 在分散式環境中,相同的業務應用分佈在不同的機器上,有些業務邏輯(例如一些耗時的計算,網路I/O處理),往往只需要讓整個叢集中的某一臺機器進行執行,其餘機器可以共享這個結果,這樣可以大大減少
ZooKeeper系列之十:ZooKeeper的一致性保證及Leader選舉
1)一致性保證 Zookeeper 是一種高效能、可擴充套件的服務。 Zookeeper 的讀寫速度非常快,並且讀的速度要比寫的速度更快。另外,在進行讀操作的時候, ZooKeeper 依然能夠為舊的資料提供服務。這些都是由於 ZooKeepe 所提供的一致性保證,它具有如下特點: 順序一致性
Zookeeper -- leader選舉
Zookeeper的核心是源自廣播,實現這個機制的協議是Zab協議。Zab協議有兩種模式,分別是恢復模式和廣播模式。當伺服器啟動或者領導者崩潰後,Zab就進入了恢復模式,當領導者被選舉出來,且大多數Server完成了和leader的狀態同步以後,恢復模式就結