溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SOFAJRaft的實現(xiàn)原理是什么

發(fā)布時間:2021-07-09 17:38:13 來源:億速云 閱讀:282 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“SOFAJRaft的實現(xiàn)原理是什么”,在日常操作中,相信很多人在SOFAJRaft的實現(xiàn)原理是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”SOFAJRaft的實現(xiàn)原理是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

SOFAStackScalable Open Financial  Architecture Stack) 是螞蟻金服自主研發(fā)的金融級分布式架構(gòu),包含了構(gòu)建金融級云原生架構(gòu)所需的各個組件,是在金融場景里錘煉出來的最佳實踐。

SOFAJRaft 是一個基于 Raft 一致性算法的生產(chǎn)級高性能 Java 實現(xiàn),支持 MULTI-RAFT-GROUP,適用于高負載低延遲的場景。

本文為《剖析 | SOFAJRaft 實現(xiàn)原理》第六篇,本篇作者徐家鋒,來自專偉信息,力鯤,來自螞蟻金服?!镀饰?| SOFAJRaft 實現(xiàn)原理》系列由 SOFA 團隊和源碼愛好者們出品,項目代號:<SOFA:JRaftLab/>,文章尾部有參與方式,歡迎同樣對源碼熱情的你加入。

SOFAJRaft :https://github.com/sofastack/sofa-jraft

本文的目的是要介紹 SOFAJRaft 在日志復制中所采用的 pipeline 機制,但是作者落筆時突然覺得這個題目有些唐突,我們不應(yīng)該假設(shè)讀者理所應(yīng)當?shù)膶θ罩緩椭七@個概念已經(jīng)了然于胸,所以作為一篇解析,我覺得還是應(yīng)該先介紹一下 SOFAJRaft 中的日志復制是要解決什么問題。

概念介紹

SOFAJRaft 是對 Raft 共識算法的 Java 實現(xiàn)。既然是共識算法,就不可避免的要對需要達成共識的內(nèi)容在多個服務(wù)器節(jié)點之間進行傳輸,在 SOFAJRaft 中我們將這些內(nèi)容封裝成一個個日志塊 (LogEntry),這種服務(wù)器節(jié)點間的日志傳輸行為在 SOFAJRaft 中也就有了專門的術(shù)語:日志復制。

為了便于閱讀理解,我們用一個象棋的故事來類比日志復制的流程和可能遇到的問題。

假設(shè)我們穿越到古代,要為一場即將舉辦的象棋比賽設(shè)計直播方案。當然所有電子通訊技術(shù)此時都已經(jīng)不可用了,幸好象棋比賽是一種能用精簡的文字描述賽況的項目,比如:“炮二平五”, “馬8進7”, “車2退3”等,我們將這些描述性文字稱為棋譜。這樣只要我們在場外同樣擺上棋盤 (可能很大,方便圍觀),通過棋譜就可以把棋手的對弈過程直播出來。

SOFAJRaft的實現(xiàn)原理是什么cdn.nlark.com/yuque/0/2019/png/307286/1564466968889-f553ceba-e385-41ca-90be-97020fb9a656.png">

圖1 - 通過棋譜直播

所以我們的直播方案就是:賽場內(nèi)兩位棋手正常對弈,設(shè)一個專門的記錄員來記錄棋手走出的每一步,安排一個旗童飛奔于賽場內(nèi)外,棋手每走一步,旗童就將其以棋譜的方式傳遞給場外,這樣觀眾就能在場外準實時的觀看對弈的過程,獲得同觀看直播相同的體驗。

SOFAJRaft的實現(xiàn)原理是什么

圖2 - 一個簡單的直播方案

這便是 SOFAJRaft 日志復制的人肉版,接下來我們完善一下這個“直播系統(tǒng)”,讓它逐步對齊真實的日志復制。

改進1. 增加記錄員的數(shù)量

假設(shè)我們的比賽獲得了很高的關(guān)注度,我們需要在賽場外擺出更多的直播場地以供更多的觀眾觀看。

SOFAJRaft的實現(xiàn)原理是什么

這樣我們就要安排更多的旗童來傳遞棋譜,場外的每一臺直播都需要一個旗童來負責,這些旗童不停的在賽場內(nèi)外奔跑傳遞棋譜信息。有的直播平臺離賽場遠一些,旗童要跑很久才行,相應(yīng)的直播延遲就會大一些,而有些直播平臺離得很近,對應(yīng)的旗童就能很快的將對弈情況同步到直播。

隨著直播場地的增加,負責記錄棋局的記錄員的壓力就會增加,因為他要針對不同的旗童每次提供不同的棋譜內(nèi)容,有的慢有的快。如果記錄員一旦記混了或者眼花了,就會出現(xiàn)嚴重的直播事故(觀眾看到的不再是棋手真正的棋局)。

SOFAJRaft的實現(xiàn)原理是什么

圖4 - 壓力很大的記錄員

為此我們要作出一些優(yōu)化,為每個場外的直播平臺安排一個專門的記錄員,這樣 “賽局-記錄員-旗童-直播局” 就構(gòu)成了單線模式,專人專職高效可靠。

SOFAJRaft的實現(xiàn)原理是什么

圖5 - “賽局-記錄員-旗童-直播棋局”

改進2. 增加旗童每次傳遞的信息量

起初我們要求棋手每走一步,旗童就向外傳遞一次棋譜。可是隨著比賽進行,其弊端也逐漸顯現(xiàn),一方面記錄員記錄了很多棋局信息沒有傳遞出去,以至于不得不請求棋手停下來等待 (不可思議);另一方面,場外的觀眾對于這種“卡幀”的直播模式也很不滿意。

所以我們做出改進,要求旗童每次多記幾步棋,這樣記錄員不會積攢太多的待直播信息,觀眾也能一次看到好幾步,而這對于聰明的旗童來說并不是什么難事,如此改進達到了共贏的局面。

SOFAJRaft的實現(xiàn)原理是什么

圖6 - 旗童批量攜帶信息

改進3. 增加快照模式

棋局愈發(fā)精彩,應(yīng)棋迷的強烈要求,我們臨時增加了幾個直播場地,這時棋手已經(jīng)走了很多步了,按照我們的常規(guī)手段,負責新直播的記錄員和旗童需要把過去的每一步都在直播棋盤上還原一遍(回放的過程),與此同時棋手還在不斷下出新的內(nèi)容。

從直覺上來說這也是一種很不聰明的方式,所以這時我們采用快照模式,不再要求旗童傳遞過去的每一步棋譜,而是把當前的棋局圖直接描下來,旗童將圖帶出去后,按照圖譜直接擺子。這樣新直播平臺就能快速追上棋局進度,讓觀眾欣賞到賽場同步的棋局對弈了。

SOFAJRaft的實現(xiàn)原理是什么

圖7 - 采用快照模式

改進4. 每一個直播平臺用多個旗童傳遞信息

雖然我們之前已經(jīng)在改進 2 中增加了旗童每次攜帶的信息量,但是在一些情況下(棋手下快棋、直播平臺很遠等),記錄員依然無法將信息及時同步給場外。這時我們需要增加多個旗童,各旗童有次序的將信息攜帶到場外,這樣記錄員就可以更快速的把信息同步給場外直播平臺。

SOFAJRaft的實現(xiàn)原理是什么

圖8 - 利用多個旗童傳遞信息,實現(xiàn) pipeline 效果

現(xiàn)在這個人肉的直播平臺在我們的逐步改進下已經(jīng)具備了 SOFAJRaft 日志復制的下面幾個主要特點:

特點1: 被復制的日志是有序且連續(xù)的

如果棋譜傳遞的順序不一樣,最后下出的棋局可能也是完全不同的。而 SOFAJRaft 在日志復制時,其日志傳輸?shù)捻樞蛞惨WC嚴格的順序,所有日志既不能亂序也不能有空洞 (也就是說不能被漏掉)。

SOFAJRaft的實現(xiàn)原理是什么

圖9 - 日志保持嚴格有序且連續(xù)

特點2: 復制日志是并發(fā)的

SOFAJRaft 中 Leader 節(jié)點會同時向多個 Follower 節(jié)點復制日志,在 Leader 中為每一個 Follower 分配一個 Replicator,專用來處理復制日志任務(wù)。在棋局中我們也針對每個直播平臺安排一個記錄員,用來將對弈棋譜同步給對應(yīng)的直播平臺。

SOFAJRaft的實現(xiàn)原理是什么

圖10 - 并發(fā)復制日志

特點3: 復制日志是批量的

SOFAJRaft 中 Leader 節(jié)點會將日志成批的復制給 Follower,就像旗童會每次攜帶多步棋信息到場外。

SOFAJRaft的實現(xiàn)原理是什么

圖11 - 日志被批量復制

特點4: 日志復制中的快照

在改進 3 中,我們讓新加入的直播平臺直接復制當前的棋局,而不再回放過去的每一步棋譜,這就是 SOFAJRaft 中的快照 (Snapshot) 機制。用 Snapshot 能夠讓 Follower 快速跟上 Leader 的日志進度,不再回放很早以前的日志信息,即緩解了網(wǎng)絡(luò)的吞吐量,又提升了日志同步的效率。

特點5: 復制日志的 pipeline 機制

在改進 4 中,我們讓多個旗童參與信息傳遞,這樣記錄員和直播平臺間就可以以“流式”的方式傳遞信息,這樣既能保證信息傳遞有序也能保證信息傳遞持續(xù)。

在 SOFAJRaft 中我們也有類似的機制來保證日志復制流式的進行,這種機制就是 pipeline。Pipeline 使得 Leader 和 Follower 雙方不再需要嚴格遵從 “Request - Response - Request” 的交互模式,Leader 可以在沒有收到 Response 的情況下,持續(xù)的將復制日志的 AppendEntriesRequest 發(fā)送給 Follower。

在具體實現(xiàn)時,Leader 只需要針對每個 Follower 維護一個隊列,記錄下已經(jīng)復制的日志,如果有日志復制失敗的情況,就將其后的日志重發(fā)給 Follower。這樣就能保證日志復制的可靠性,具體細節(jié)我們在源碼解析中再談。

SOFAJRaft的實現(xiàn)原理是什么

圖12 - 日志復制的 pipeline 機制

源碼解析

上面就是日志復制在原理層面的介紹,而在代碼實現(xiàn)中主要是由 Replicator 和 NodeImpl 來分別實現(xiàn) Leader 和 Follower 的各自邏輯,主要的方法列于下方。在處理源碼中有三點值得我們關(guān)注。

SOFAJRaft的實現(xiàn)原理是什么

圖13 - 相關(guān)的方法

關(guān)注1: Replicator 的 Probe 狀態(tài)

SOFAJRaft的實現(xiàn)原理是什么

圖14 - Replicator 的狀態(tài)

Leader 節(jié)點在通過 Replicator 和 Follower 建立連接之后,要發(fā)送一個 Probe 類型的探針請求,目的是知道 Follower 已經(jīng)擁有的的日志位置,以便于向 Follower 發(fā)送后續(xù)的日志。

SOFAJRaft的實現(xiàn)原理是什么

圖15 - 發(fā)送探針來知道 follower 的 logindex

關(guān)注2: 用 Inflight 來輔助實現(xiàn) pipeline

Inflight 是對批量發(fā)送出去的 logEntry 的一種抽象,他表示哪些 logEntry 已經(jīng)被封裝成日志復制 request 發(fā)送出去了。

SOFAJRaft的實現(xiàn)原理是什么

圖16 - Inflight 結(jié)構(gòu)

Leader 維護一個 queue,每發(fā)出一批 logEntry 就向 queue 中 添加一個代表這一批 logEntry 的 Inflight,這樣當它知道某一批 logEntry 復制失敗之后,就可以依賴 queue 中的 Inflight 把該批次 logEntry 以及后續(xù)的所有日志重新復制給 follower。既保證日志復制能夠完成,又保證了復制日志的順序不變。

這部分從邏輯上來說比較清晰,但是代碼層面需要考慮的東西比較多,所以我們在此處貼出源碼,讀者可以在源碼中繼續(xù)探索。

SOFAJRaft的實現(xiàn)原理是什么

圖17 - 復制日志的主要方法

SOFAJRaft的實現(xiàn)原理是什么

圖18 - 添加 Inflight 到隊列中

當然在日志復制中其實還要考慮更加復雜的情況,比如一旦發(fā)生切換 leader 的情況,follower 該如何應(yīng)對,這些問題希望大家能夠進入源碼來尋找答案。

關(guān)注3: 通信層采用單線程 & 單鏈接

在 pipeline 機制中,雖然我們在 SOFAJRaft 層面通過 Inflight 隊列保證了日志是被有序的復制,對于亂序傳輸?shù)?LogEntry 通過各種異常流程去排除掉,但是這些被排除掉的亂序日志最終還是要通過重傳來保證最終成功,這就會影響日志復制的效率。

SOFAJRaft的實現(xiàn)原理是什么

圖19 - 通信層不能保證有序

如上圖所示,發(fā)送端的 Connection Pool 和 接收端的 Thread Pool 都會讓原本“單行道”上有序傳輸?shù)娜罩具M入“多車道”,因而無法保證有序。所以在通信層面 SOFAJRaft 做了兩部分優(yōu)化去盡量保證 LogEntry 在傳輸中不會亂序。

  1. 在 Replicator 端,通過 uniqueKey 對日志傳輸所用的 Url 進行特殊標識 ,這樣 SOFABolt (SOFAJRaft 底層所采用的通信框架) 就會為這種 Url 建立單一的連接,也就是發(fā)送端的 Connection Pool 中只有一條可用連接。

SOFAJRaft的實現(xiàn)原理是什么

圖20 - 通過 uniqueKey 定制 Url

  1. 在接收端不采用線程池派發(fā)任務(wù),增加判斷 _dispatch_msg_list_in_default_executor_ 使得我們可以通過 io 線程直接將任務(wù)投遞到 Processor 中。我們對 SOFABolt 做過一些功能增強,這里提供相關(guān) PR #84 ,有興趣的讀者可以前往了解。

 SOFAJRaft的實現(xiàn)原理是什么

圖21 - SOFABolt 利用 IO 線程派發(fā) AppendEntriesRequest 到 Processor

這樣日志復制的通信模型就變成了我們期望的“單行道”的模式。這種“單行道”能夠很大程度上保證傳輸?shù)娜罩臼怯行蚯疫B續(xù)的,從而提升了 pipeline 的效率。

SOFAJRaft的實現(xiàn)原理是什么

圖22 - 優(yōu)化通信模型

總結(jié)

日志復制并不是一個復雜的概念,pipeline 機制也是一種符合直覺思維的優(yōu)化方式,甚至在我們的日常生活中也能找到這些概念的實踐。在 SOFAJRaft 中,日志復制的真正難點是如何在分布式環(huán)境下既考慮到各種細節(jié)和異常,又保證高性能。本文只是從概念上嘗試介紹了日志復制,更多的細節(jié)還需讀者進入代碼去尋找答案。

到此,關(guān)于“SOFAJRaft的實現(xiàn)原理是什么”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI