因此該候選者就成為了Leader領(lǐng)導(dǎo)人,它可以向選民也就是Follower們發(fā)出指令,比如進(jìn)行日志復(fù)制;
如果一旦Leader宕機(jī)崩潰了,那么Follower中會(huì)有一個(gè)成為候選者,發(fā)出選舉邀請(qǐng);
Follower同意后,其成為L(zhǎng)eader;
選出leader之后,所有的操作都需要在leader上進(jìn)行,leader把所有的操作下發(fā)到集群中的其他服務(wù)器(follower),follower收到消息,完成操作commit之后需要向leader匯報(bào)狀態(tài);如果leader處于不可用的狀態(tài),則需要重新進(jìn)行選舉。
為了與容錯(cuò)方式達(dá)成一致性,Raft不要求所有的服務(wù)器100%達(dá)成一致,只要超過(guò)半數(shù)的服務(wù)器達(dá)成一致就可以了,假設(shè)有N臺(tái)服務(wù)器,N/2+1超過(guò)半數(shù),也就是說(shuō)一個(gè)3節(jié)點(diǎn)的Raft集群允許一個(gè)節(jié)點(diǎn)宕機(jī),一個(gè)5節(jié)點(diǎn)的Raft集群可以允許2個(gè)節(jié)點(diǎn)宕機(jī),所以為了更有效的利用服務(wù)器,一般Raft集群里服務(wù)器的數(shù)量都是奇數(shù),建議配置運(yùn)行3或5節(jié)點(diǎn)的Raft集群, 最大限度的提高可用性, 而且不會(huì)犧牲很多性能。
三、實(shí)踐:如何自己動(dòng)手寫一個(gè)內(nèi)置Raft集群的分布式服務(wù)
下面結(jié)合swan中的具體代碼,介紹如何啟動(dòng)RaftNode,以及處理數(shù)據(jù)和有關(guān)Raft狀態(tài)的相關(guān)實(shí)踐,swan的分布式存儲(chǔ)的設(shè)計(jì)草圖如下:
如何啟動(dòng)一個(gè)RaftNode
先分享下如何自己動(dòng)手寫一個(gè)內(nèi)置Raft集群的分布式服務(wù),由于是使用Go語(yǔ)言開(kāi)發(fā),所以選用etcd/raft。
在Raft集群中最重要的概念就是一個(gè)RaftNode,多個(gè)互相連通的RaftNode組成了一個(gè)RaftCluster,可以通過(guò)以下代碼快速啟動(dòng)/重啟一個(gè)RaftNode。
該方法是在RaftNode啟動(dòng)時(shí)已經(jīng)知道集群未來(lái)的規(guī)模,將集群的其他節(jié)點(diǎn)ID寫入到配置中,如果要實(shí)現(xiàn)節(jié)點(diǎn)的Auto Join,則需要在Start的Peers參數(shù)處傳入空值;另外,如果服務(wù)之前已經(jīng)運(yùn)行了一段時(shí)間,在啟動(dòng)服務(wù)時(shí)就需要從WAL中讀取上一次服務(wù)停止時(shí)的狀態(tài)和數(shù)據(jù),然后在這些數(shù)據(jù)的基礎(chǔ)上繼續(xù)運(yùn)行。
RaftNode啟動(dòng)成功后,各個(gè)節(jié)點(diǎn)之間的通信需要借助一個(gè)Transport,同樣還是使用etcd提供的httptransport ,當(dāng)然,也可以基于grpc實(shí)現(xiàn)所有的通信方法(參考swarmkit的實(shí)現(xiàn)),以下是啟動(dòng)transport的代碼實(shí)現(xiàn)。