天天看點

ceph存儲 ceph叢集Leader選舉

Paxos算法存在活鎖問題。從節點中選出Leader,然後将所有對資料的修改都通過Leader作為提案提出,可以讓算法快速收斂。Leader的選舉規則是,由目前活動的Monitor節點中rank值最小的節點當選。選舉不僅會産生Leader還将确定Quorum成員,Quorum成員就是那些支援新Leader節點當選Leader的節點。是以,雖然不能保證Leader的rank值是所有節點中最小的,但是可以保證它的值在Quorum中是最小的。Quorum是Monitor中的多數派,也就是說它的成員數目必須大于N/2+1,N為Monitor節點數目。

Leader選舉過程大緻可以分成以下3個步驟:首先,Proposer提出提案,發送propose消息給所有的Monitor節點。其次,Monitor節點(Acceptor)接收到proposer消息,如果接受提案則回複ack消息。最後,Proposer統計接收到的ack消息,向其它節點發送victory消息宣布赢得Leader選舉并同步資料。

提出propose消息

在選舉Leader過程中,epoch擔當非常重要的角色。它有以下幾個方面的作用:

1) 代表邏輯時間。正常情況下,Quorum中各個節點的epoch值應該是相等的。當節點離線後,它的epoch值被儲存在資料庫中,重新上線後它的epoch值比其它節點的小。在處理propose消息時,Acceptor節點根據epoch值來判斷消息是不是最新的。

2) 用于判斷目前節點是否處于Leader選舉狀态。當epoch為奇數時,說明節點處于選舉狀态;選舉結束後,epoch值會遞增為偶數并同步到所有的Quorum成員。

Proposer提出選舉提案前,先從資料庫中讀取epoch值,并将其遞增到奇數。

處理propose消息

ceph存儲 ceph叢集Leader選舉

Acceptor處理propose消息時,主要考慮epoch(代表時間)和rank兩個因素:首先,判斷propose消息是否是由于網絡延遲導緻的舊提案,若是則拒絕提案;其次,判斷proposer的rank值是否是它知道的rank中最小的,若是則接受并且承諾不接受rank值比提案的rank值更大的提案。

處理ack消息

Ack消息對應Paxos的Accept消息。

ceph存儲 ceph叢集Leader選舉

Ack消息有兩個作用:一種情況是通知Proposer它的提案被發送ack消息的Acceptor接受了;另一種情況是,Acceptor已經接受了提案(因為它的rank值小于Acceptor),但是存在提案号更高的提案,Proposer應該放棄目前的提案,使用更高的提案号重新提出提案。

例子

假設原來已經存在兩個節點A和B,現在加入新節點C,并且節點C的rank值是三者中最小的。節點C加入時,将引發選舉:

1) 節點C向其餘兩個節點發送propose消息,将自己設定為Leader。由于節點C是新加入的,是以它的epoch值從0開始遞增;

2) 節點A、B接受到消息後,發現節點C的epoch值比較舊。但由于節點C不在Quorum中,說明這個提案不是由于網絡延遲導緻的舊提案。并且節點C的rank值比自己小,是以接受提案并提醒對方更新epoch值。

3) 節點C接收到節點A和B的ack消息,發現自己的epoch值比它們都小,是以用它們的epoch更新自己,并重新發送propose消息,提出提案。

4) 節點A、B接受到新propose消息,發現節點C的epoch值比自己的新,于是更新自己的epoch值(持久化到磁盤)。另外,節點C的rank值也比自己的小,是以接受提案。

5) 節點C接收到節點A和B對新提案的Ack消息,赢得選舉。

6) 節點C向其餘節點發送victory消息,更新Quorum以及Leaders角色。

如果新加入節點的rank值的不是最小的,那麼當它的proposer消息發送到rank值比自己更小的節點時,會引發節點提出提案參加候選。這種情況下,新節點雖然不會赢得選舉,但是能夠讓自己加入到Quorum多數派。

疑問:多Leader情況

假設有A到E共5個節點,它們的rank值是依次遞增的。另外,A和B之間互相不通。當5個節點的epoch都相同,節點A和B同時提出提案(此時提案的epoch也相同)。

-----------------------
     A   B   C  D  E  
A    +   -   +  +  +
B    -   +   +  +  +
-----------------------
           

如果B的propose先達到C、D和E節點,那麼這三個節點都會接受B節點的提案。這樣,節點B就獲得了多數派的支援,選舉逾時後它将赢得選舉。當節點A的propose消息到達C、D和E節點時,由于A節點的rank值要比它們已經接受的B節點的rank值小,是以這三個節點将接受A節點的提案。

這樣,節點A和節點B都認為赢得了選舉,都将自己初始化為Leader,都可以接受來自用戶端對Cluster map的修改。

這種情況下,如果節點A的propose消息早于B節點的消息到達C、D、E中兩個或兩個以上的節點時,B節點将不能赢得選舉。因為Acceptor承諾不接受rank值更大的提案,B節點後達到時将被拒絕。

其它

變量說明

start_stamp: 提出提案的時間戳
acked_me: 回複ack消息的節點集合
electing_me: “選我”,标記自己為候選人
leader_acked: 接受的提案的内容,沒接受提案時該值預設為-1;
           

接口說明

1、選舉的入口函數為Monitor::start_election(),進入該函數時将Monitor的狀态更改為STATE_ELECTING。Elector::start()為private方法,必須經過Elector::call_election()方法調用;
2、選舉成功後進入Monitor::win_election()函數将Monitor狀态修改為STATE_LEADER,選舉失敗的節點進入Monitor::lose_election()函數将Monitor的狀态修改為STATE_PEON;
           

參考資料

1、ceph work flow

2、MONITOR CONFIG REFERENCE