天天看點

分布式一緻性--手撸raft-demo & sofa-jraft優點

作者:JAVA互聯搬磚勞工
分布式一緻性--手撸raft-demo & sofa-jraft優點

前言

我最近在研究sofa相關架構,裡面有sofa-jraft,主要是實作分布式一緻性算法,作為一個新手去直接看源碼會暈在裡面的,是以我打算先去官網了解raft算法,然後自己手撸一套,最後看sofa-jraft架構跟我寫的有什麼不一樣。

這樣既能了解raft原理,通過動手實作加深印象,最後發現原本raft算法上問題,sofa-jraft相應的解決方案又是什麼。

什麼是raft

raft官網:raft.github.io/

分布式一緻性--手撸raft-demo & sofa-jraft優點

簡單講:raft有兩個核心流程:選舉、日志同步,它的理念是這樣的

選舉

1、一個任期裡面隻有一個leader,強leader概念,就像一山隻能一隻老虎,不然就亂套了對吧;

2、其次每個節點都有機會變成候選人,邏輯就是每個節點本身有個定時器,當我這個定時器到期的時候,沒有收到leader的心跳可以自立為王;(這很好了解,就是當leader當機的時候,跟随者可以重新選舉的,避免群龍無主的情況)

3、作為leader的邏輯:投給你票的數量,占整個叢集的數量/2+1,你可以當老大啦,相當民主吧

4、節點數量不少于等于3

日志同步

1、有leader之後,它要幹兩件事,第一件是心跳,我還在你們别搞事,繼續當follower,哈哈哈。第二件事是日志同步,當有資料更新的時候,leader節點會先寫到日志log裡面,然後同步到其他節點,當同步成功的數量占叢集數量/2+1,說明叢集大家贊同這次操作,那leader會最終将它應用到狀态機

2、leader狀态機應用之後,可以通過心跳讓其他節點應用到各自狀态機的。

上面我們提到幾個東西:節點、日志、狀态機,他們具體的關系是這樣的

分布式一緻性--手撸raft-demo & sofa-jraft優點

講解,大概有5步,我們可以看到選舉的結果就是有一個leader節點,若幹跟随者,外部client設定數值的時候,會給leader去處理,如果發到follower的話,同樣也需要轉發給老大處理。

首先是應用到日志裡面,就是跟大家講有這麼一回事,有人要往我這塞錢,硬塞那種哈哈,小弟們收到這個消息之後,也記錄下這麼一件事,然後大家決定記錄好之後跟老大回報,老大根據節點儲存情況,來最終拍闆這錢收的話,就應用到狀态機,這就是闆上釘釘的事了,然後再把這個同步給各個小弟。

如果以後有人來查賬,直接從leader的狀态機查,我們可以清晰的知道,節點是來選出老大的,日志是一種暫時儲存的地方,而狀态機是闆上釘釘的資料,自此完成了分布式一緻性。

至于整個過程,大家可以去raft官網玩一下,這樣可以增加對概念的了解。

手撸raft-demo

我就按照我的了解,手撸了raft-demo,具體的位址:github.com/dajitui/jav… ,因為是簡易版的,是以很多實作方式比較簡單粗暴,比如說rpc通過map來儲存資料,然後日志對比,如果不一緻直接日志、狀态機重新拷貝,去除一個一個對比的過程。

裡面有兩個demo,一個是3個節點選舉,然後設定值的過程,另一個是4個節點,然後一個節點逾時重新選舉的demo。

介紹

裡面我分為幾個子產品:一緻性子產品、日志子產品、狀态機子產品、rpc子產品、節點子產品、定時器子產品

一緻性子產品

1、選舉、投票算法

日志子產品

1、選型:rocksdb,初始化、新增、擷取

2、lastlogindex,rocksdb并沒有自帶這個功能

3、批量重置,因為是暴力做法,就是隻要節點資料不一緻的話,直接全部重置,省去了對比的過程

狀态機子產品

1、選型:rocksdb,初始化、新增、擷取

2、同上

3、批量應用,重置完日志之後,也得應用狀态機對吧

rpc子產品

1、通過本地map來儲存,key是node唯一表示serviceid,value 是string類型,通過特定的契約來解碼

2、節點定時摟資料

節點子產品

1、定義節點屬性,是否是leader節點、選舉投票情況(候選人節點專屬)、節點角色(leader、follower、候選人)、所有節點、日志子產品、狀态機子產品、定時器子產品...

定時器子產品

1、選舉定時器

2、心跳定時器(leader節點專屬)

一套下來的感受

1、所有節點資訊儲存問題

這裡我并沒有說通過第三方中間件來解決這個問題,因為引入多一個中間件,那麼架構的穩定性就越差,如果每個節點都存所有資料資訊的時候,那他們怎麼做到這個資料的同步呢?

答案也是很明顯,就按照raft的算法作為資料在叢集進行同步。

2、選舉、心跳、新增日志操作缺點什麼

沒錯,缺點同步,因為很多共享變量,這時就需要上鎖,我們往後再看看jraft怎麼解決的。

3、雖然我有分别列印各個節點的情況,但是很麻煩,因為開發或者示範的時候,需要定時列印這個叢集的情況

帶上上面幾個問題,我們來看看sofa-jraft架構的實作

sofa-jraft

sofa-jraft 是螞蟻下面sofastack社群的一個開源架構,主要實作分布式一緻性的功能,官網位址:github.com/sofastack/s… ,大家感興趣自行閱讀。

優點

1、減少term數值疊加

我們通過raft算法可以知道,當一個節點失聯的時候、網絡分區的時候,那麼它的任期會很大很大,最緻命的是它會打斷正常叢集的作業,就像我們玩得好好的,忽然說你們先停下,我剛剛斷網了,重新選個老大重玩,哈哈哈。

是以第一個理念,減少任期的疊加,為了實作這個功能就引出第二點preVote,預先投票,如果大家不同意你當老大,那麼你乖乖回到之前的任期。

2、在第一點上需要預選舉

3、投過誰的票有效期,raft一個任期隻能投一票,導緻任期一直疊加的結果

在raft算法裡面,每個任期節點隻能給一個人投票,而在jraft架構裡面節點的投票,它是有有限期的,因為為了實作預選舉,如果你一個任期隻能投一個,那慘了,預選舉失敗那麼你這個節點就投不了票了,是以投票結果也有過期時間。

4、快照,當一個節點起來、當機的時候,快速恢複日志

這是額外的東西,就是當一個新節點加入的時候,如果一個日志一個日志同步很慢,這時就需要一個快照可以嗖~直接給幹完。

5、心跳當日志新增傳輸,隻是内容為空

在我自己開發的raft-demo裡面,心跳是單獨一個定時器,其實可以跟日志整合一個定時器,隻不過data為空,這也是一個節省的方法

6、在操作的時候如果是對象最好再copy一個,技巧型

我們再回到上面幾個問題,sofa-jraft是這麼處理的。

所有節點資訊儲存問題

1、所有節點隻在leader節點存,直接寫到日志,通過日志複制,如果當機可以從日志取所有節點,相當于所有節點是作為資訊在叢集同步

com.alipay.sofa.jraft.storage.impl.LogManagerImpl#appendEntries ConfigurationEntry

選舉邏輯

2、prevote投票的時候,先投給自己,然後建立一個Ballot,quorum法定人數,如果它大于總node數/2+1則擷取leader位置

邏輯優化

3、邏輯上修正:當選leader之後,leader節點選舉定時器關掉

同步問題

4、采用讀寫鎖,reentranreadwritelock、stamplock

總結

我們最後總結一下sofa-jraft的東西,它比raft額外加多了prevote+投票有效期+快照,使得raft算法有了一個提升,更加可靠;其次對于一些共享資料,比如所有節點的資訊,其實也需要跟叢集内部同步的,是以也是作為日志的一部分進行記錄,靠譜滴~

這個raft-demo搞了3-4天吧,滿滿的成就感,接下來學paxos,下一篇文章見~

原文連結:https://juejin.cn/post/7243727901782097981

繼續閱讀