91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

SOFAJRaft的實現原理是什么

發布時間:2021-07-09 17:38:13 來源:億速云 閱讀:289 作者:chen 欄目:大數據

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

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

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

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

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

本文的目的是要介紹 SOFAJRaft 在日志復制中所采用的 pipeline 機制,但是作者落筆時突然覺得這個題目有些唐突,我們不應該假設讀者理所應當的對日志復制這個概念已經了然于胸,所以作為一篇解析,我覺得還是應該先介紹一下 SOFAJRaft 中的日志復制是要解決什么問題。

概念介紹

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

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

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

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

圖1 - 通過棋譜直播

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

SOFAJRaft的實現原理是什么

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

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

改進1. 增加記錄員的數量

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

SOFAJRaft的實現原理是什么

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

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

SOFAJRaft的實現原理是什么

圖4 - 壓力很大的記錄員

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

SOFAJRaft的實現原理是什么

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

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

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

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

SOFAJRaft的實現原理是什么

圖6 - 旗童批量攜帶信息

改進3. 增加快照模式

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

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

SOFAJRaft的實現原理是什么

圖7 - 采用快照模式

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

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

SOFAJRaft的實現原理是什么

圖8 - 利用多個旗童傳遞信息,實現 pipeline 效果

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

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

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

SOFAJRaft的實現原理是什么

圖9 - 日志保持嚴格有序且連續

特點2: 復制日志是并發的

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

SOFAJRaft的實現原理是什么

圖10 - 并發復制日志

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

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

SOFAJRaft的實現原理是什么

圖11 - 日志被批量復制

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

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

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

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

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

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

SOFAJRaft的實現原理是什么

圖12 - 日志復制的 pipeline 機制

源碼解析

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

SOFAJRaft的實現原理是什么

圖13 - 相關的方法

關注1: Replicator 的 Probe 狀態

SOFAJRaft的實現原理是什么

圖14 - Replicator 的狀態

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

SOFAJRaft的實現原理是什么

圖15 - 發送探針來知道 follower 的 logindex

關注2: 用 Inflight 來輔助實現 pipeline

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

SOFAJRaft的實現原理是什么

圖16 - Inflight 結構

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

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

SOFAJRaft的實現原理是什么

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

SOFAJRaft的實現原理是什么

圖18 - 添加 Inflight 到隊列中

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

關注3: 通信層采用單線程 & 單鏈接

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

SOFAJRaft的實現原理是什么

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

如上圖所示,發送端的 Connection Pool 和 接收端的 Thread Pool 都會讓原本“單行道”上有序傳輸的日志進入“多車道”,因而無法保證有序。所以在通信層面 SOFAJRaft 做了兩部分優化去盡量保證 LogEntry 在傳輸中不會亂序。

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

SOFAJRaft的實現原理是什么

圖20 - 通過 uniqueKey 定制 Url

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

 SOFAJRaft的實現原理是什么

圖21 - SOFABolt 利用 IO 線程派發 AppendEntriesRequest 到 Processor

這樣日志復制的通信模型就變成了我們期望的“單行道”的模式。這種“單行道”能夠很大程度上保證傳輸的日志是有序且連續的,從而提升了 pipeline 的效率。

SOFAJRaft的實現原理是什么

圖22 - 優化通信模型

總結

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

到此,關于“SOFAJRaft的實現原理是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

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

AI

黄陵县| 崇义县| 盐城市| 平凉市| 桐庐县| 五台县| 略阳县| 林甸县| 贡觉县| 东山县| 遵义市| 宿松县| 泸溪县| 晋中市| 大丰市| 中方县| 安康市| 渭源县| 民乐县| 高碑店市| 图们市| 双柏县| 班戈县| 乌苏市| 宾川县| 乌鲁木齐县| 松潘县| 梁平县| 固镇县| 广宗县| 通海县| 双牌县| 尚义县| 渑池县| 襄汾县| 铜梁县| 达拉特旗| 苍梧县| 额济纳旗| 云阳县| 原平市|