raft 學(xué)習(xí)筆記(6.824 Lab 2)

raft 學(xué)習(xí)筆記

最近在學(xué)習(xí) 6.824 的分布式課程.
學(xué)習(xí)到 Raft 算法. 寫篇文章作為記錄.

什么是 Raft

Raft 是一個用于管理分布式副本一致性的算法, 設(shè)計的目的是為了使分布式一致性更加容易理解和實現(xiàn).

算法細(xì)節(jié)

目前實現(xiàn)的 Raft 算法主要包含兩個部分, 一個是領(lǐng)導(dǎo)者選舉, 另外一個是日志復(fù)制.

領(lǐng)導(dǎo)者選舉

在 Raft 算法中存在三種角色, 領(lǐng)導(dǎo)者/候選人/跟隨者. 有兩個時間的概念, 心跳時間(固定時間)/選舉超時時間(隨機時間).
在初始狀態(tài)下, 所有的角色都是候選人, 等到選舉超時時間到的時候發(fā)起選舉投票, 如果得到半數(shù)以上的選票則變?yōu)轭I(lǐng)導(dǎo)者.

當(dāng)角色變成領(lǐng)導(dǎo)者之后要立即對所有的成員發(fā)起心跳請求, 以鞏固領(lǐng)導(dǎo)者的地位(阻止其他成員繼續(xù)發(fā)起投票請求). 如果一個
成員收到了心跳請求, 則變成跟隨者角色, 并作出響應(yīng).

日志復(fù)制

日志復(fù)制的的請求使伴隨在心跳請求中的, 也就是說如果存在沒有同步給其他成員的日志, 則在心跳的時候附帶上這些日志.
對于客戶端的請求, 只有復(fù)制到大多數(shù)成員的時候才認(rèn)為這個請求使可提交的狀態(tài), 領(lǐng)導(dǎo)者提交之后也要通知其他成員提交.

Raft 算法實現(xiàn)

在 6.824 的課程當(dāng)中提供了一個骨架以及一些測試用例, 目標(biāo)是實現(xiàn)提供的接口, 最終通過所有的測試. 下面是論文中的實現(xiàn)方式.

所有服務(wù)器都需要存儲的狀態(tài)

在回復(fù) RPCs 的響應(yīng)之前保存到磁盤

  1. currentTerm 服務(wù)器所經(jīng)歷的最后一屆領(lǐng)導(dǎo)人 (初始化為 0, 單調(diào)遞增)
  2. votedFor 當(dāng)前任期(上面的currentTerm)獲取投票的候選人ID
  3. log[] log隊列, 每個log實體包含一個給狀態(tài)機的命令和領(lǐng)導(dǎo)人收到時的任期號(第一個索引號為1)

所有服務(wù)器變化的狀態(tài)

  1. commitIndex 服務(wù)器知道的最高的應(yīng)該提交的log實體編號(初始化為 0, 單調(diào)遞增).
  2. lastApplied 服務(wù)器應(yīng)用到狀態(tài)機的log實體最高編號(初始化為0, 單調(diào)遞增)

領(lǐng)導(dǎo)人經(jīng)常變化的狀態(tài)

贏得選舉之后需要重新初始化.

  1. nextIndex[] 維護每個服務(wù)器下一個需要發(fā)送的log實體的編號(初始化為領(lǐng)導(dǎo)人最新的log實體編號 加 1).
  2. matchIndex[] 維護每個服務(wù)器得到確認(rèn)的最大log實體編號.

所有成員需要實現(xiàn)的接口(RPC)

請求選舉的 RPC

用于候選人調(diào)用獲得選票

參數(shù)列表
  1. term 候選人的任期號
  2. candidateId 候選人ID
  3. lastLogIndex 候選人的最新log實體的編號.
  4. lastLogTerm 候選人的最新log實體的任期號
返回值
  1. term 當(dāng)前任期號(currentTerm), 用于候選人更新自己
  2. voteGranted true 表示投票給該候選人
接受者的實現(xiàn)
  1. 如果 term < currentTerm 返回 false.
  2. 如果 votedFor 狀態(tài)為空, 或者為請求中的 candidateId, 并且候選人的 log 至少跟接受者的日志一樣新, 則投出選票 true, 否則 false.

復(fù)制 log 的 RPC

用于領(lǐng)導(dǎo)人調(diào)用來復(fù)制log實體. 也用于維持心跳.

參數(shù)列表
  1. term 領(lǐng)導(dǎo)人的任期號
  2. leaderId 領(lǐng)導(dǎo)人 ID, 用于跟隨者可以轉(zhuǎn)發(fā)請求
  3. prevLogIndex 上一個 log 的索引號.
  4. prevLogTerm 上一個 log 的任期號.
  5. entries[] 需要存儲的 log (心跳的這個字段為空; 為了提高效率可能會發(fā)送多個)
  6. leaderCommit 領(lǐng)導(dǎo)人的 commitIndex
返回值
  1. term 當(dāng)前任期(currentTerm), 用于領(lǐng)導(dǎo)人更新自己
  2. success 如果接受者存在與 prevLogIndex 和 prevLogTerm 匹配的日志則返回 true
接收者實現(xiàn)
  1. 如果 term < currentTerm 返回 false.
  2. 如果接收者的log隊列中不包含與 prevLogIndex 和 prevLogTerm 匹配的日志, 返回 false.
  3. 如果接收者存在一個 log 與發(fā)來的 log prevLogIndex 匹配但是 prevLogTerm 不匹配, 則刪掉這個 log 及之后所有的 log.
  4. 把所有不存在于 log 隊列中的 log, 添加到隊列中
  5. 如果 leaderCommit > commitIndex, 則 commitIndex = min(leaderCommit, 新發(fā)來的 log 的 index)

所有服務(wù)器都應(yīng)該遵守的規(guī)則

所有服務(wù)器

  1. 如果 commitIndex > lastApplied, 增加 lastApplid, 應(yīng)用 log[lastapplied] 到狀態(tài)機中
  2. 如果 RPC 請求或者響應(yīng)當(dāng)中包含的任期 T > currentTerm, 則 currentTerm = T, 并且自己轉(zhuǎn)換到跟隨者狀態(tài).

跟隨者

  1. 響應(yīng)來自候選人和領(lǐng)導(dǎo)人的 RPC.
  2. 如果選舉時間超時, 并且沒有收到附加日志(或者心跳)的 RPC, 也沒用收到選舉請求, 則自己轉(zhuǎn)變?yōu)楹蜻x人

候選人

  1. 當(dāng)轉(zhuǎn)變?yōu)楹蜻x人的時候, 開始選舉:
    1. 增加currentTerm
    2. 給自己投票
    3. 重置選舉超時計時器
    4. 發(fā)送 RequestVote RPC 給所有服務(wù)器
  2. 如果收到大多數(shù)服務(wù)器的支持選票則變?yōu)轭I(lǐng)導(dǎo)人
  3. 如果收到了一個新的領(lǐng)導(dǎo)人的附加日志的RPC 或者 心跳, 則轉(zhuǎn)變?yōu)楦S者
  4. 如果選舉超時, 開始一輪新的選舉(跳轉(zhuǎn)到步驟 1)

領(lǐng)導(dǎo)人

  1. 贏得選舉之后不斷發(fā)送心跳給所有的服務(wù)器, 防止超時
  2. 如果收到客戶端命令: 首先添加到本地的日志隊列, 在應(yīng)用到狀態(tài)機之后應(yīng)答客戶端.
  3. 如果最新的log編號>= 跟隨者的 nextIndex 編號: 從 nextIndex 索引號開始發(fā)送附加log的 RPC.
    1. 如果成功: 更新跟隨者的 nextIndex 和 matchIndex
    2. 如果因為 log 不匹配而失敗: 減小 nextIndex 的值并且重試.
  4. 如果存在一個 N, 這個 N 滿足: N > commitIndex, 并且 大多數(shù)跟隨者的 matchIndex[i] >= N, 并且 log[N].term == currentTerm, 那么就讓 commitIndex = N.

現(xiàn)在只實現(xiàn)了選舉和日志復(fù)制兩部分內(nèi)容, 關(guān)于集群的變更等內(nèi)容后續(xù)會繼續(xù)實現(xiàn), 課程中后續(xù)還會基于這個實現(xiàn)的基礎(chǔ)上
來實現(xiàn)一個分布式的 KV存儲.

最后附上代碼地址: https://gist.github.com/icodinglife/910869da89a2e62a1b4deae994fb8d0b

由于剛剛接觸 golang, 對于一些用法還不是太熟悉, 代碼中有一些比較丑陋或者錯誤的設(shè)計和用法, 后續(xù)隨著不斷熟悉和深入
會慢慢重構(gòu)掉. 歡迎大家討論拍磚提意見 : )

歡迎打賞, 鼓勵我堅持下去~~~ : )

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容