日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

科普: 中间件底层实现的分布式协议之Raft

發(fā)布時間:2024/2/28 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 科普: 中间件底层实现的分布式协议之Raft 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

正式介紹 Raft 協(xié)議之前,我們先來舉一個例子🌰進(jìn)行展開。

方式一:

在一個技術(shù)團(tuán)隊內(nèi)假設(shè)角色都是?均等的,會導(dǎo)致什么情況呢?產(chǎn)品提出一個需求,就可以隨便去找團(tuán)隊中的任意一個人去發(fā)起需求。如果這個人因為請假走了,但是他沒有把需求及時同步給團(tuán)隊其他人,因此會導(dǎo)致該需求存在很大的延遲。

方式二:

在技術(shù)團(tuán)隊中選舉一個?Leader 角色,產(chǎn)品提出的需求必須優(yōu)先提給 Leader,找 Leader 先溝通。Leader 自己消化完后,在將需求傳達(dá)給團(tuán)隊其他成員。如果 Leader 請假了,會指定某一個人充當(dāng) Leader 角色負(fù)責(zé)接收產(chǎn)品需求,并將需求同步給其他成員。

上述很簡單的案例,可以對應(yīng)理解分布式系統(tǒng)中的數(shù)據(jù)一致性算法。

分布式系統(tǒng)數(shù)據(jù)一致性算法一般都應(yīng)用在中間件項目中,平時你寫的業(yè)務(wù)代碼,一般根本不會接觸到的。

SpringCloud 家族中集成了大名鼎鼎的注冊中心 Eureka?,就使用的上面的?方式一?的思路來完成節(jié)點之間數(shù)據(jù)同步的,稱為?Peer To Peer?集群架構(gòu)。

Eureka 當(dāng)中的每個節(jié)點的地位都是均等的,每個節(jié)點都可以接收寫入請求,每個節(jié)點接收請求之后,進(jìn)行請求打包處理,異步化延遲一點時間,將數(shù)據(jù)同步給 Eureka 集群當(dāng)中的其他節(jié)點。任何一臺節(jié)點宕機之后,理論上應(yīng)該是不影響集群運行的,都可以從其他節(jié)點獲取注冊表信息。

另外的一些開源項目采用?方式二?的思路,比如 Etcd、Consul,Redis-Sentinel、Zookeeper,還有未來會流行的國產(chǎn)技術(shù)阿里開源的 Nacos 項目,其中的 CP 模式也是基于?Raft 協(xié)議?來實現(xiàn)分布式一致性算法的。當(dāng)然 Zookeeper 在 Raft 協(xié)議基礎(chǔ)上做了一些改良,使用的 ZAB 分布式一致性協(xié)議來實現(xiàn)的。

在 Raft 協(xié)議出現(xiàn)之前,廣泛使用的一致性算法是 Paxos。Paxos 算法解決的是如何保障單一客戶端操作的一致性,完成每個操作都需要至少兩輪的消息交換。和 Paxos 算法不同,Raft 里有 Leader 的概念,Raft 在處理任何客戶端操作之前必須要選舉出來一個 leader 角色,選舉一個 Leader 經(jīng)過至少一輪的消息交換,但是選舉了 Leader 之后,處理每個客戶端的操作只需要一輪消息交換。

詳解 Raft 協(xié)議

?

接下來,圍繞如下幾點展開:

1)Leader選舉流程

2)節(jié)點心跳檢測

3)選主超時操作

4)日志復(fù)制流程

5)日志條目結(jié)構(gòu)

6)Leader崩潰恢復(fù)操作

1)Leader選舉流程

?

如果系統(tǒng)中只有唯一一個節(jié)點,讀寫操作都由這一個節(jié)點來負(fù)責(zé),不會存在數(shù)據(jù)不一致的問題。

但是,對于分布式系統(tǒng)會存在至少兩個節(jié)點,需要有一個角色來充唯一的節(jié)點,我們把這個唯一節(jié)點叫做?Leader 節(jié)點,其他節(jié)點叫做?Follower 節(jié)點, leader 選舉過程中才會有的狀態(tài)叫做?Candidate 節(jié)點。

?

為了便于理解和說明,假設(shè)集群中有三個節(jié)點:節(jié)點A、節(jié)點B、節(jié)點C。

集群啟動后,初始節(jié)點狀態(tài)都是 Follower 狀態(tài)。最開始各個節(jié)點啟動之后,此時集群內(nèi)還沒有 Leader。

?

如果每次各節(jié)點都投票給自己,Leader 會始終無法選出來,這樣僵持下去肯定是不行的。所以出現(xiàn)了 electionTimeout 的概念,稱為?選舉超時時間?每個節(jié)點都會有 electionTimeout。

一旦發(fā)現(xiàn)一輪投票沒有結(jié)果,集群中各節(jié)點自身設(shè)置一個 electionTimeout,時間范圍在 150ms ~ 300ms 之間的一個隨機值。

?

當(dāng)節(jié)點 A 的 electionTimeout 時間到了,會將節(jié)點 A 狀態(tài)變?yōu)?Candidate 狀態(tài),節(jié)點 A 蘇醒過來,很Happy,終于可以參與競選了,立馬給自己投了一票 。然后向集群中其他兩個節(jié)點發(fā)起選舉投票(Http協(xié)議或者RPC協(xié)議請求都可以)。

節(jié)點B、C可以認(rèn)為處于 Follower 狀態(tài),如何進(jìn)行選舉投票呢?

這里就出現(xiàn)了?term?的概念,每個節(jié)點都會有個 term,term 表示任期,跟美國總統(tǒng)競選里的任期類似。term 是一個全局且連續(xù)遞增的整數(shù),每完成一次選舉,term會遞增 +1。

Follower 狀態(tài)的節(jié)點此時收到 Candidate 選舉請求,發(fā)現(xiàn)集群中就只有一個 Candidate 狀態(tài)的節(jié)點 A,所以直接投票給 Candidate 節(jié)點。

這里就出現(xiàn)了?voteFor?的概念,每個節(jié)點都會有voteFor,voteFor 表示投票的數(shù)據(jù)。

節(jié)點 A 收到投票反饋之后,引出了另外的判斷條件:必須是集群中過半節(jié)點都投票給自己,也包括自己。

算式:n / 2 + 1

舉個🌰:

集群中有三個節(jié)點,3 / 2 + 1 = 2 必須有 2 個節(jié)點投票成功。

集群中有五個節(jié)點,5 / 2 + 1 = 3 必須有 3 個節(jié)點投票成功。

最終 Candidate 狀態(tài)的節(jié)點 A 很榮幸晉升為 Leader。

2)節(jié)點心跳檢測

我們看到上述的狀態(tài)流轉(zhuǎn)圖,當(dāng)重新選舉 Leader 時,各節(jié)點自身的狀態(tài)會在 Candidate、Follower、Leader 之間不斷的變換。

所以,被選舉的節(jié)點 A 成為了 Leader ,為了保持它的『統(tǒng)治』地位,要不斷的向其他節(jié)點發(fā)送心跳,告訴他們「我還活著,我還活著... 」。

其他節(jié)點 B、C 收到心跳請求后,會返回響應(yīng),發(fā)現(xiàn)原來 Leader 還在,不需要發(fā)起選舉,同時要重置選舉超時時間 electionTimeout。

如果作為 Leader 的節(jié)點 A 因為意外,比如網(wǎng)絡(luò)問題無法正常發(fā)送心跳給其他節(jié)點。

此時,節(jié)點 B 的 electionTimeout 超時時間到了,變成了 Candidate 狀態(tài),term + 1,voteFor 投票給自己,并發(fā)送投票請求給節(jié)點 A、C。

之前還是 Leader 的節(jié)點 A 收到了節(jié)點 B 發(fā)來的投票請求,發(fā)現(xiàn) term 任期不是最大的了,更新自身的 term 值為節(jié)點 B 的 term,從 Leader 狀態(tài)切換為 Follower 狀態(tài),并重置 electionTimeout。

3)選主超時操作

?

如果恰巧有兩個節(jié)點同時都發(fā)起了投票,但都沒有獲得多數(shù)節(jié)點的選票,此時就得打加時賽了,直到獲得多數(shù)選票的節(jié)點成為 Leader。

如下圖所示:

?

假設(shè)集群中有4個節(jié)點,A、B、C、D。出現(xiàn)了兩個節(jié)點處于 Candidate 狀態(tài)。

第一輪選舉狀態(tài)如下:

節(jié)點A[Candidate] <----- 節(jié)點 C 選舉節(jié)點A節(jié)點B[Candidate] <----- 節(jié)點 D 選舉節(jié)點B

第一輪選舉之后,節(jié)點 A 和節(jié)點 B 還是處于 Candidate 狀態(tài),都不滿足集群過半數(shù)投票成功的條件,選舉 Leader 失敗。

下一輪就要看 Candidate 狀態(tài)的節(jié)點誰的 electionTimeout 先到,誰就先發(fā)起新一輪選舉操作。只要發(fā)起選舉,term 任期就要遞增的。

如果節(jié)點 B 的 electionTimeout 先到,先發(fā)起選舉操作,那么集群中按照條件必須是有 3 個節(jié)點投票成功之后最終成為 Leader。

為了避免出現(xiàn)上述這種平局的情況,所以一般集群中節(jié)點部署個數(shù)都是奇數(shù):?2n + 1

?

4)日志復(fù)制流程

?

當(dāng) Leader 選出來之后,Client 客戶端發(fā)起的寫請求都會由 Leader 節(jié)點來處理。

即使其他的 Follower 節(jié)點收到了 Client 客戶端的請求,也會將請求轉(zhuǎn)交給 Leader 來處理。

Leader 接收到 Client 的請求之后,會優(yōu)先將數(shù)據(jù)寫入到自身節(jié)點的 log 日志文件中。

被寫入到日志文件里的日志條目,被稱為?append entries?。

Leader 將發(fā)送 append entries 消息給其他節(jié)點,這里并不是每次都將相同的日志條目,都發(fā)送給其他節(jié)點,而是根據(jù)節(jié)點的不同對應(yīng)的消息也是不同的。因為集群中節(jié)點之間數(shù)據(jù)可能會有不一致的情況。

其他 Follower 節(jié)點收到 Leader 的消息后,將數(shù)據(jù)添加到本地,然后返回給 Leader 響應(yīng),確認(rèn)消息已收到。

Leader 節(jié)點收到其他節(jié)點確認(rèn)消息且過半數(shù),先 Commit 提交記錄,返回 Client 客戶端響應(yīng)。

然后,Leader 節(jié)點再次向其他 Follower 節(jié)點發(fā)送 Commit 提交數(shù)據(jù)通知。

其他 Follower 節(jié)點收到通知后,Commit 提交自身的日志條目數(shù)據(jù),返回 Leader 更新結(jié)束的通知。

日志條目提交保證兩點:

容錯:

在數(shù)量少于 Raft 服務(wù)器節(jié)點總數(shù)一半的 Follower 失敗的情況下 ,Raft 集群仍然可以正常處理來自客戶端的請求。

確保重疊:

一旦 Leader 響應(yīng)了一個客戶端的請求,即使出現(xiàn)了 Raft 集群中少數(shù)服務(wù)器的失敗,也會有一個服務(wù)器包含所有以前提交的日志條目。

?

5)日志條目結(jié)構(gòu)

?

每個節(jié)點都會有兩個索引,日志條目最終提交完成,提交的索引值稱為?commitIndex,另外一個是目前最后一行索引值,稱為?lastApplied

Leader 節(jié)點除了存儲上面提到的 commitIndex 和 lastApplied之外,還需要存儲其他 Follower 節(jié)點的數(shù)據(jù)情況。

一個是?nextIndex?記錄的是 Leader 里有,Follower 節(jié)點沒有的數(shù)據(jù)索引,即需要發(fā)送 append entries 的數(shù)據(jù)索引。

另外一個是?matchIndex?,記錄的是 Leader 節(jié)點已知,已經(jīng)復(fù)制給他 Follower 節(jié)點日志的最高索引值。

當(dāng)數(shù)據(jù)變更時, Leader 向其他節(jié)點發(fā)送不同的 append entries 消息數(shù)據(jù)。

如果重新選舉了 Leader,新的 Leader 并不知道原來 Leader 的 nextIndex 和 matchIndex 兩個數(shù)據(jù),會將自身節(jié)點的 nextIndex 重置為 commitIndex,matchIndex 則全部重置為 0。

?

6)選主后日志同步

?

當(dāng)集群中的 Leader 接收到 Client 請求,發(fā)現(xiàn)部分節(jié)點因為網(wǎng)絡(luò)問題無法正常通訊,所以日志不能復(fù)制給多數(shù)節(jié)點,日志無法正常提交。

如下圖所示:

其他 Follower 節(jié)點無法正常收到 Leader 心跳檢測請求,會發(fā)生重新選主操作。

當(dāng)新的 Leader1 產(chǎn)生,原來的 Leader2 集群恢復(fù)之后,發(fā)現(xiàn)自己不是選票最多的節(jié)點,即 term 不是最大的,節(jié)點狀態(tài)切換到 Follower,回滾未提交的日志。

新的 Leader1 重新將同步日志重新同步給其他 Follower 節(jié)點。

如下圖所示 :

?

總結(jié)

?

經(jīng)過對 Raft 協(xié)議的詳細(xì)分析,我們能夠總結(jié)到,其實 Raft 協(xié)議就是?2PC (兩階段提交) + 集群過半節(jié)點寫機制?結(jié)合實現(xiàn)的。

1、每個節(jié)點都有 electionTimeout 選舉超時時間,用于當(dāng) Follower 節(jié)點無法收到心跳時,到期發(fā)起選舉 Leader 的操作。

2、Leader 節(jié)點選舉時,最終選出來的 Leader 的 term 任期一定是最大的。

3、Leader 節(jié)點給其他 Follower 節(jié)點發(fā)送 append enties 日志條目時,針對不同的節(jié)點發(fā)送不同的日志消息。

4、Leader 接收客戶端的寫入請求,此時處于 uncommitted 狀態(tài),Leader 將 uncommitted 消息發(fā)送給其他 Follower 節(jié)點,作為第一階段。

5、其他 Follower 節(jié)點收到 uncommitted 請求之后,返回確認(rèn) ack 響應(yīng)給 Leader,如果 Leader 收到了過半數(shù) Follower 節(jié)點的 ack 響應(yīng),則將請求標(biāo)記為 committed,同時發(fā)送 committed 請求發(fā)送給其他 Follower 節(jié)點,讓其他節(jié)點對消息進(jìn)行 committed。作為第二階段 + 過半數(shù)機制。

另外,剛剛文中提到阿里開源的 Nacos 注冊中心,其內(nèi)部自己實現(xiàn)了一套簡化版的 Raft 協(xié)議。看了 Nacos 官方的 Roadmap 能夠了解到,規(guī)劃在 Nacos 1.7.0 GA 中會替換掉現(xiàn)在的 Raft 協(xié)議實現(xiàn),有可能會采用螞蟻金服開源的SOFA-JRaft,SOFA-JRaft 基于 Raft 一致性算法的生產(chǎn)級高性能 Java 實現(xiàn),支持 MULTI-RAFT-GROUP,適用于高負(fù)載低延遲的場景。

?

參考:

http://ifeve.com/raft/?

http://thesecretlivesofdata.com/raft/

總結(jié)

以上是生活随笔為你收集整理的科普: 中间件底层实现的分布式协议之Raft的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。