Raft 演算法詳解(二)日誌複製

2021-10-06 10:53:14 字數 3028 閱讀 9673

在 raft 演算法中,副本資料是以日誌的形式存在的,領導者接收到來自客戶端寫請求後,處 理寫請求的過程就是乙個複製和提交日誌項的過程。

那 raft 是如何複製日誌的呢?又如何實現日誌的一致的呢?這些內容是 raft 中非常核心 的內容,首先,咱 們先來理解日誌,這是你掌握如何複製日誌、實現日誌一致的基礎。

如何理解日誌?

剛剛我提到,副本資料是以日誌的形式存在的,日誌是由日誌項組成,日誌項究竟是什麼樣 子呢?

其實,日誌項是一種資料格式,它主要包含使用者指定的資料,也就是指令(command), 還包含一些附加資訊,比如索引值(log index)、任期編號(term)。那你該怎麼理解 這些資訊呢?

指令:一條由客戶端請求指定的、狀態機需要執行的指令。你可以將指令理解成客戶端 指定的資料。

索引值:日誌項對應的整數索引值。它其實就是用來標識日誌項的,是乙個連續的、單 調遞增的整數號碼。

任期編號:建立這條日誌項的領導者的任期編號。

從圖中你可以看到,一屆領導者任期,往往有多條日誌項。而且日誌項的索引值是連續的, 這一點你需要注意

講到這兒你可能會問:不是說 raft 實現了各節點間日誌的一致嗎?那為什麼圖中 4 個跟隨 者的日誌都不一樣呢?日誌是怎麼複製的呢?又該如何實現日誌的一致呢?別著急,接下來 咱們就來解決這幾個問題。先來說說如何複製日誌。

如何複製日誌?

你可以把 raft 的日誌複製理解成乙個優化後的二階段提交(將二階段優化成了一階段), 減少了一半的往返訊息,也就是降低了一半的訊息延遲。那日誌複製的具體過程是什麼呢?

接著,如果領導者接收到大多數的「複製成功」響應後,它將日誌項提交到它的狀態機,並 返回成功給客戶端。如果領導者沒有接收到大多數的「複製成功」響應,那麼就返回錯誤給 客戶端。

學到這裡,有同學可能有這樣的疑問了,領導者將日誌項提交到它的狀態機,怎麼沒通知跟 隨者提交日誌項呢?

這是 raft 中的乙個優化,領導者不直接傳送訊息通知其他節點提交指定日誌項。因為領導 者的日誌複製 rpc 訊息或心跳訊息,包含了當前最大的,將會被提交的日誌項索引值。所 以通過日誌複製 rpc 訊息或心跳訊息,跟隨者就可以知道領導者的日誌提交位置資訊。

因此,當其他節點接受領導者的心跳訊息,或者新的日誌複製 rpc 訊息後,就會將這條日 志項提交到它的狀態機。而這個優化,降低了處理客戶端請求的延遲,將二階段提交優化為 了一段提交,降低了一半的訊息延遲。

我們後再走一遍這個過程,這樣可以更加全面地掌 握日誌複製。

接收到客戶端請求後,領導者基於客戶端請求中的指令,建立乙個新日誌項,並附加到 本地日誌中。

不過,這是乙個理想狀態下的日誌複製過程。在實際環境中,複製日誌的時候,你可能會遇 到程序崩潰、伺服器宕機等問題,這些問題會導致日誌不一致。那麼在這種情況下,raft 演算法是如何處理不一致日誌,實現日誌的一致的呢?

如何實現日誌的一致?

在 raft 演算法中,領導者通過強制跟隨者直接複製自己的日誌項,處理不一致日誌。也就是 說,raft 是通過以領導者的日誌為準,來實現各節點日誌的一致的。具體有 2 個步驟。

首先,領導者通過日誌複製 rpc 的一致性檢查,找到跟隨者節點上,與自己相同日誌項 的最大索引值。也就是說,這個索引值之前的日誌,領導者和跟隨者是一致的,之後的 日誌是不一致的了。

然後,領導者強制跟隨者更新覆蓋的不一致日誌項,實現日誌的一致。

我們來詳細地走一遍這個過程(為了方便演示,我們引入 2 個新變數)。

prevlogentry:表示當前要複製的日誌項,前面一條日誌項的索引值。比如在圖中,如 果領導者將索引值為 8 的日誌項傳送給跟隨者,那麼此時 prevlogentry 值為 7。

prevlogterm:表示當前要複製的日誌項,前面一條日誌項的任期編號,比如在圖中, 如果領導者將索引值為 8 的日誌項傳送給跟隨者,那麼此時 prevlogterm 值為 4。

領導者通過日誌複製 rpc 訊息,傳送當前最新日誌項到跟隨者(為了演示方便,假設當 前需要複製的日誌項是最新的),這個訊息的 prevlogentry 值為 7,prevlogterm 值 為 4。

如果跟隨者在它的日誌中,找不到與 prevlogentry 值為 7、prevlogterm 值為 4 的日 志項,也就是說它的日誌和領導者的不一致了,那麼跟隨者就會拒絕接收新的日誌項, 並返回失敗資訊給領導者。

這時,領導者會遞減要複製的日誌項的索引值,並傳送新的日誌項到跟隨者,這個訊息 的 prevlogentry 值為 6,prevlogterm 值為 3。

如果跟隨者在它的日誌中,找到了 prevlogentry 值為 6、prevlogterm 值為 3 的日誌 項,那麼日誌複製 rpc 返回成功,這樣一來,領導者就知道在 prevlogentry 值為 6、 prevlogterm 值為 3 的位置,跟隨者的日誌項與自己相同。

領導者通過日誌複製 rpc,複製並更新覆蓋該索引值之後的日誌項(也就是不一致的日 志項),最終實現了集群各節點日誌的一致。

從上面步驟中你可以看到,領導者通過日誌複製 rpc 一致性檢查,找到跟隨者節點上與自 己相同日誌項的最大索引值,然後複製並更新覆蓋該索引值之後的日誌項,實現了各節點日 志的一致。需要你注意的是,跟隨者中的不一致日誌項會被領導者的日誌覆蓋,而且領導者 從來不會覆蓋或者刪除自己的日誌。

Raft演算法系列教程3 日誌複製

客戶端的每乙個請求都包含被複製狀態機執行的指令。leader把這個指令作為一條新的日誌條目新增到日誌中,然後並行發起 rpc 給其他的伺服器,讓它們複製這條資訊。假如這條日誌被安全的複製,leader就應用這條日誌到自己的狀態機中,並返回給客戶端。如果follower宕機或者執行緩慢或者丟包,lea...

Kafka日誌儲存解析(二)日誌索引

每個日誌分段檔案對應了兩個索引檔案,主要用來提高查詢訊息的效率。如上圖 kafka中的索引檔案屬於稀疏索引,不是所有的訊息都有對應的索引項。每當寫入一定量 由broker端引數log.index.interval.bytes指定,預設是4kb 的訊息時,偏移量索引檔案和時間戳索引檔案分別增加乙個偏移...

Java開發手冊之異常日誌(二) 日誌規約

強制 應用中不可直接使用日誌系統 log 4 j logback 中的 api 而應依賴使用日誌框架slf 4 j 中的 api 使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。import org.slf4j.logger import org.slf4j.logge ctory p...