- 為什么需要 Raft?
- Raft 是什么?
- Raft 的目標
- 前置條件:復制狀態機
- Raft 基礎
- Leader 選舉(選舉安全特性)
- 日志復制(Leader只附加、日志匹配)
- 安全
- 學習資料
- 使用 Raft 的應用?
- 擴展:ZooKeeper ZAB 協議
- 擴展:ZooKeeper 是什么?
為什么需要 Raft?
- 要提高
系統的容錯率
,需要分布式系統 - 分布式系統有多個實例,對於給定的一組操作,需要協議讓
所有實例達成一致
(分布式一致性) - Paxos 是分布式一致性協議的標准,但難以理解、實現
- Raft 提供了和 Paxos 算法相同的功能,但更好理解、構建實際的系統
Raft 是什么?
- Replicated And Fault Tolerant,
復制和容錯
- 管理復制
日志的一致性算法
Raft 的目標
- 簡單易理解
- 提供完整的實現系統,減少開發者的工作量
- 保證所有條件下都是安全的,在大部分情況下是可用的
- 常用操作是高效的
前置條件:復制狀態機
- Raft 相當於復制狀態機中的“
一致性模塊
” - 一致性模塊(Consensus Module):管理來自客戶端的指令,接入 log
- 日志(Log)
- 狀態機(State Machine):執行日志的指令,得到 Server 狀態
Raft 基礎
- 節點狀態:
Leader(領導者)
:系統只有一個節點處是 Leader,處理所有客戶端的請求並同步給 FollowerFollower(跟隨者)
:只響應其他服務器(Leader、Candidate)的請求Candidate(候選者)
:在選舉領導的時候出現
- term(任期):
- 一段選舉的任期(選舉開始+正常工作)
- term 號自動 +1
- 如果選票均分,則該 term 直接結束,進入下一個 term
- Raft 中的
「邏輯時鍾」
,可發現過期信息,規則:- 每個節點會存儲當前 term 號,term 編號單調遞增
- 節點間通信,交換 term 號
- (1)節點當前 term 號 < 他人 term 號,更新 term 號
- (2)節點當前 term 號 > 他人 term 號,拒絕請求
- (3)Candidate、Leader 發現自己的 term < 他人 term,立即變成 Follower
- 節點通信:使用
RPC
- 請求投票(RequestVote) RPCs:選舉階段,Candidate 節點發送給他人
- 附加條目(AppendEntries)RPCs:非選舉階段,Leader 發給所有節點,復制日志+心跳
- 特性(Raft 保證在任何時候都成立)
- 選舉安全:對一個給定的 term 號,最多選舉出一個 Leader
- Leader 只附加原則:Leader 不會刪除、覆蓋自己的日志,只會增加
- 日志匹配:若兩個日志在相同索引位置的日志的 term 號相同,則日志從頭到該索引位置全部相同
- Leader 完整特性:選舉出的 Leader,會包含所有已提交的日志
- 狀態機安全特性:Leader 已經將給定的索引值位置的日志條目應用到狀態機,其他任何服務器都已執行
Leader 選舉(選舉安全特性)
- Raft 使用心跳機制觸發 Leader 選舉
- 集群存在 Leader,Leader 節點周期性發心跳包
- 一個 Follower 沒有收到任何消息(固定區間隨機的時間),發起選舉
- 集群啟動時,所有節點都處於 Follower 狀態
- 節點到達超時時間后,會進入 Candidate 狀態,增加自己的 term 號,發送請求投票給自己
- Candidate 狀態機
- 節點得票最多的,變成 Leader
- 收到來自其他節點的“聲明自己是 Leader”的請求
- 一段時間后,沒有獲得多數票,也沒有收到其他節點的 Leader 通知(平分選票)
- 避免選舉的平分選票:隨機選舉超時時間
- 每個節點隨機選擇選舉超時時間,到達時間后成為 Candidate
- 大多數情況下,只有一個節點率先進入 Candidate
日志復制(Leader只附加、日志匹配)
- Leader 會接收客戶端的請求,請求指令作為一個“日志條目”添加到日志中
- 向所有 Follower 發送附加條目 RPC,讓他們復制這個日志條目
- 得到大多數節點回復后,Leader 會把日志寫入復制狀態機,持久化,把執行結果返回給客戶端
- 日志非安全的;進入狀態機中是安全的(已提交),最終會被所有可用的狀態機執行。
index = 7 的日志已經被大多數節點復制,狀態為已提交。
安全
- 選舉限制(Leader 完整性):每次選舉出來的 Leader,必須包含所有已提交的日志
- 只有已經被大部分節點復制的日志,才會變成“已提交”
- 一個 Candidate 必須得到大部分節點投票,才能變成 Leader
- 投票時,節點不會把票投給沒有自己的日志新的 Candidate
- Follower 或 Candidate 崩潰:無限重試
- 超時和可用性:broadcastTime(廣播時間)<< electionTimeout(選舉超時時間)<< MTBF(平均故障間隔時間)
學習資料
使用 Raft 的應用?
- 服務發現框架:consul、
etcd
- 日志:
RocketMQ
- 數據存儲:
Tidb
、k8s
擴展:ZooKeeper ZAB 協議
- 支持崩潰恢復的原子廣播協議:
ZooKeeper Atomic Broadcast protocol
- ZooKeeper 適合
讀多寫少
的場景,客戶端隨機連到 ZK 集群的一個節點- 從當前節點讀
- 寫入到 leader,leader 廣播事務,半數節點成功才會被提交
整體流程類似於 Raft
,只是細節和實現的區別
擴展:ZooKeeper 是什么?
官方定義: A Distributed Coordination Service for Distributed Applications。本質:基於內存的 KV 系統,以 path 為 key
。
代碼、思維導圖筆記鏈接
代碼和思維導圖在 GitHub 項目中,歡迎大家 star!
coding 筆記、點滴記錄,以后的文章也會同步到公眾號(Coding Insight)中,希望大家關注_