Raft 誕生背景:
分布式存儲(chǔ)系統(tǒng)通常通過(guò)維護(hù)多個(gè)副本來(lái)進(jìn)行容錯(cuò),提高系統(tǒng)的可用性。要實(shí)現(xiàn)此目標(biāo),就必須要解決分布式存儲(chǔ)系統(tǒng)的最核心問(wèn)題:維護(hù)多個(gè)副本的一致性。
首先需要解釋一下什么是一致性(consensus),它是構(gòu)建具有容錯(cuò)性(fault-tolerant)的分布式系統(tǒng)的基礎(chǔ)。 在一個(gè)具有一致性的性質(zhì)的集群里面,同一時(shí)刻所有的結(jié)點(diǎn)對(duì)存儲(chǔ)在其中的某個(gè)值都有相同的結(jié)果,即對(duì)其共享的存儲(chǔ)保持一致。集群具有自動(dòng)恢復(fù)的性質(zhì),當(dāng)少數(shù)結(jié)點(diǎn)失效的時(shí)候不影響集群的正常工作,當(dāng)大多數(shù)集群中的結(jié)點(diǎn)失效的時(shí)候,集群則會(huì)停止服務(wù)(不會(huì)返回一個(gè)錯(cuò)誤的結(jié)果)
高可用:
多副本架構(gòu)是云原生的基礎(chǔ),也是高可用、分布式架構(gòu)場(chǎng)景中常見(jiàn)的一種架構(gòu)解決方案。對(duì)于應(yīng)用服務(wù)、數(shù)據(jù)庫(kù)、中間件服務(wù)來(lái)說(shuō)高可用是一種共識(shí)追求的目標(biāo),很多公司也會(huì)有很多高可用衡量指標(biāo):
衡量指標(biāo):
-
PRO。Recovery Point Objective (RPO),是災(zāi)難(或中斷)可能導(dǎo)致的數(shù)據(jù)(事務(wù))丟失的最長(zhǎng)目標(biāo)時(shí)間,與數(shù)據(jù)恢復(fù)點(diǎn)設(shè)置有關(guān),主要指的是業(yè)務(wù)系統(tǒng)所能容忍的數(shù)據(jù)丟失量,由業(yè) 務(wù)連續(xù)性規(guī)劃定義。RPO不宜過(guò)長(zhǎng),以免數(shù)據(jù)丟失過(guò)多。
-
RTO。Recovery Time Objective (RTO) ,是災(zāi)難(或中斷)后必須恢復(fù)業(yè)務(wù)流程的目標(biāo)持續(xù)時(shí)間和服務(wù)級(jí)別, 主要指的是所能容忍的業(yè)務(wù)停止服務(wù)的最長(zhǎng)時(shí)間,也就是從災(zāi)難發(fā)生到業(yè)務(wù)系統(tǒng)恢復(fù)服務(wù)功能所需要的最短時(shí)間周期。RTO不宜過(guò)長(zhǎng),以避免與業(yè)務(wù)連續(xù)性中斷相關(guān)的不可接受的后果
-
SLA。Service Level Agreements (SLA)指的是與用戶協(xié)商好的可容忍數(shù)據(jù)修復(fù)時(shí)長(zhǎng),一般以“幾個(gè)9”來(lái)衡量:
-
99%或2個(gè)9:相當(dāng)于每年3天15小時(shí)36分鐘的停機(jī)時(shí)間。
-
99.9%或3個(gè)9:相當(dāng)于每年8小時(shí)45分36秒的停機(jī)時(shí)間。
-
99.99%或4個(gè)9:相當(dāng)于每年52分34秒的停機(jī)時(shí)間。
-
99.999%或5個(gè)9:相當(dāng)于每年約5分鐘的停機(jī)時(shí)間。
熱門組件使用 Raft案例:
TIDB
簡(jiǎn)介:
TiDB 是 NewSql 一款很火的數(shù)據(jù)庫(kù),解決了 Mysql 對(duì)于海量數(shù)據(jù)的處理缺陷以及橫向擴(kuò)展能力(分布式),在此基礎(chǔ)上還同時(shí)擁有 ACID 的事務(wù)特性,如果之前使用過(guò)Mysql 那么學(xué)習(xí)使用 TiDB 基本沒(méi)有什么學(xué)習(xí)成本
我們重點(diǎn)來(lái)說(shuō)說(shuō) TiDB中的 TiKV,TiDB 也是采用了存算分離架構(gòu),TiKV 就是存儲(chǔ)層。
TiKV架構(gòu)
Placement Driver : Placement Driver (PD) 負(fù)責(zé)整個(gè)集群的管理調(diào)度。
Node : Node 可以認(rèn)為是一個(gè)實(shí)際的物理機(jī)器,每個(gè) Node 負(fù)責(zé)一個(gè)或者多個(gè) Store。
Store : Store 使用 RocksDB 進(jìn)行實(shí)際的數(shù)據(jù)存儲(chǔ),通常一個(gè) Store 對(duì)應(yīng)一塊硬盤。
Region : Region 是數(shù)據(jù)移動(dòng)的最小單元,對(duì)應(yīng)的是 Store 里面一塊實(shí)際的數(shù)據(jù)區(qū)間。每個(gè) Region會(huì)有多個(gè)副本(replica),每個(gè)副本位于不同的 Store ,而這些副本組成了一個(gè) Raft group。
Leader 節(jié)點(diǎn)的視角 Raft 副本同步
一階段
在第一個(gè)階段里,一份 Data 數(shù)據(jù)會(huì)被 RAFT 狀態(tài)機(jī)轉(zhuǎn)換為兩份數(shù)據(jù),一份數(shù)據(jù)轉(zhuǎn)換為 Entries,然后落盤存儲(chǔ)到 Disk,另一份數(shù)據(jù)轉(zhuǎn)換為 Message,發(fā)送給其他 Follower 節(jié)點(diǎn)。
-
應(yīng)用接受到請(qǐng)求 Data 信息
-
應(yīng)用通過(guò)調(diào)用 RAFT 的 propose 接口將 Data 數(shù)據(jù)傳遞到 RAFT 狀態(tài)機(jī)中去
-
應(yīng)用調(diào)用 Ready 函數(shù)等待 從 RAFT 中獲取 Ready 結(jié)構(gòu)體,從 Ready 結(jié)構(gòu)體中拿出 Entries 和 Message,分別進(jìn)行落盤和轉(zhuǎn)化為 MsgAppend 信息傳遞給 Follower。
-
應(yīng)用還需要調(diào)用 advance 接口,來(lái)更新 RAFT 的內(nèi)部狀態(tài),例如 Log index 信息,代表 Log Entries 已落盤。
二階段
-
Follower 收到 Message 進(jìn)行處理后 (例如落盤) 會(huì)將 Entries 的確認(rèn)信息 MsgAppend Response 發(fā)送回給 Leader,值得注意的是這個(gè) Message 中含有 Follower 已接收的最新的 Log Entries Index。
-
當(dāng) Leader 收到 Follower 節(jié)點(diǎn)的 Message 確認(rèn)信息后,將會(huì)調(diào)用 step 函數(shù)將 Message 傳遞到 RAFT,RAFT 就會(huì)更新 Follower 的狀態(tài)信息,尤其重要的是各個(gè) Follower 的 Log Index 信息。
-
應(yīng)用調(diào)用 Ready 接口后,就會(huì)將大多數(shù) Follower 確認(rèn)的 Log Entries 放到 Ready 結(jié)構(gòu)體,應(yīng)用就會(huì)收到已確認(rèn)的 Committed Entries,可以對(duì)其進(jìn)行 Apply。
-
之后依然還要調(diào)用 advance 接口,更新 RAFT 模塊的狀態(tài),例如更新 Apply Index 信息,代表已提交。
-
最后,Leader 在給 Follower 發(fā)送 HeartBeat Msg 的時(shí)候,會(huì)帶著 Leader 的 Committed Index,以此來(lái)告知 Follower 對(duì)應(yīng)的 Log Entries 已經(jīng)被提交,F(xiàn)ollower 可以進(jìn)行對(duì)應(yīng)的 Apply 流程了。
RocketMQ
簡(jiǎn)介:
在 RocketMQ 4.5 版本之前,RocketMQ 只有 Master/Slave 一種部署方式,一組 Broker 中有一個(gè) Master,有零到多個(gè) Slave,Slave 通過(guò)同步復(fù)制或異步復(fù)制方式去同步 Master 的數(shù)據(jù)。Master/Slave 部署模式,提供了一定的高可用性。
但這樣的部署模式有一定缺陷。比如故障轉(zhuǎn)移方面,如果主節(jié)點(diǎn)掛了還需要人為手動(dòng)的進(jìn)行重啟或者切換,無(wú)法自動(dòng)將一個(gè)從節(jié)點(diǎn)轉(zhuǎn)換為主節(jié)點(diǎn)。因此,我們希望能有一個(gè)新的多副本架構(gòu),去解決這個(gè)問(wèn)題。
新的多副本架構(gòu)首先需要解決自動(dòng)故障轉(zhuǎn)移的問(wèn)題,本質(zhì)上來(lái)說(shuō)是自動(dòng)選主的問(wèn)題。這個(gè)問(wèn)題的解決方案基本可以分為兩種:
-
利用第三方協(xié)調(diào)服務(wù)集群完成選主,比如 zookeeper 或者 etcd。這種方案會(huì)引入了重量級(jí)外部組件,加重部署,運(yùn)維和故障診斷成本,比如在維護(hù) RocketMQ 集群還需要維護(hù) zookeeper 集群,并且 zookeeper 集群故障會(huì)影響到 RocketMQ 集群。
-
利用 raft 協(xié)議來(lái)完成一個(gè)自動(dòng)選主,raft 協(xié)議相比前者的優(yōu)點(diǎn),是它不需要引入外部組件,自動(dòng)選主邏輯集成到各個(gè)節(jié)點(diǎn)的進(jìn)程中,節(jié)點(diǎn)之間通過(guò)通信就可以完成選主。
多副本同步架構(gòu):
?
raft 協(xié)議是復(fù)制狀態(tài)機(jī)的實(shí)現(xiàn),這種模型應(yīng)用到消息系統(tǒng)中就會(huì)存在問(wèn)題。對(duì)于消息系統(tǒng)來(lái)說(shuō),它本身是一個(gè)中間代理,commitlog 的狀態(tài)是系統(tǒng)最終的狀態(tài),并不需要狀態(tài)機(jī)再去完成一次狀態(tài)的構(gòu)建。因此 DLedger 去掉了 raft 協(xié)議中狀態(tài)機(jī)的部分,但基于 raft 協(xié)議保證 commitlog 是一致的,并且是高可用的。
副本復(fù)制流程:
在 DLedger 中,leader 向所有 follower 發(fā)送日志也是完全相互獨(dú)立和并發(fā)的,leader 為每個(gè) follower 分配一個(gè)線程去復(fù)制日志,并記錄相應(yīng)的復(fù)制的位點(diǎn),然后再由一個(gè)單獨(dú)的異步線程根據(jù)位點(diǎn)情況檢測(cè)日志是否被復(fù)制到了多數(shù)節(jié)點(diǎn)上,返回給客戶端響應(yīng)。
短暫分區(qū)避免多主&頻繁選主邏輯:
如果出現(xiàn)上圖的網(wǎng)絡(luò)分區(qū),n2 與集群中的其他節(jié)點(diǎn)發(fā)生了網(wǎng)絡(luò)隔離,按照 raft 論文實(shí)現(xiàn),n2 會(huì)一直請(qǐng)求投票,但得不到多數(shù)的投票,term 一直增大。一旦網(wǎng)絡(luò)恢復(fù)后,n2 就會(huì)去打斷正在正常復(fù)制的 n1 和 n3,進(jìn)行重新選舉。
為了解決這種情況,DLedger 的實(shí)現(xiàn)改進(jìn)了 raft 協(xié)議,請(qǐng)求投票的過(guò)程分成了多個(gè)階段,其中有兩個(gè)重要階段:WAIT_TO_REVOTE 和 WAIT_TO_VOTE_NEXT。
WAIT_TO_REVOTE 是初始狀態(tài),這個(gè)狀態(tài)請(qǐng)求投票時(shí)不會(huì)增加 term。
WAIT_TO_VOTE_NEXT 則會(huì)在下一輪請(qǐng)求投票開(kāi)始前增加 term。
對(duì)于圖中 n2 情況,當(dāng)有效的投票數(shù)量沒(méi)有達(dá)到多數(shù)量時(shí)??梢詫⒐?jié)點(diǎn)狀態(tài)設(shè)置 WAIT_TO_REVOTE,term 不會(huì)增加。通過(guò)這個(gè)方法,提高了 Dledger 對(duì)網(wǎng)絡(luò)分區(qū)的容忍性。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-606262.html
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-606262.html
?
?
?
到了這里,關(guān)于Raft 思想在架構(gòu)中實(shí)踐的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!