常見分散式理論(CAP、BASE)和一致性協定(Gosssip協定、Raft一致性演演算法)

2022-01-10 15:00:02

一、CAP理論與BASE理論:

1、什麼是 CAP 理論:

  • C:Consistency 一致性:指強一致性,分散式系統中的所有節點在同一時刻具有同樣的值、都是最新的資料副本,一致性保證了不管向哪臺伺服器寫入資料,其他的伺服器能實時同步資料

  • A:Availability 可用性:部分結點宕機不影響整個叢集對外提供服務,每次向未故障的節點傳送請求,服務節點總能保證在有限的時間內處理完成並進行響應,從使用者角度來看就是不會出現系統操作失敗或者存取超時等問題,但是系統內部可能會出現網路延遲等問題

  • P:Partition Tolerance 分割區容錯性:由於網路的問題錯綜複雜,如果某個節點因為網路等問題造成資料不一致,或者資料延遲很久才同步過來,雖然會影響部分節點資料的時效性,但是服務節點依然是可用的,分散式系統要能容忍這種情況的,也就是說,儘管網路上有部分訊息丟失,但系統仍然可繼續工作。

        分散式系統中,CAP是無法同時滿足的,只能滿足CAP中的兩種,因此在設計分散式架構時,必須做出取捨,而對於分散式系統,分割區容忍性是基本要求,必須要滿足,否則就失去了價值。因為是節點宕機和網路故障大概率事件,很難避免,而當出現這種情況時,不可能同時保持一致性和可用性,所以設計分散式系統,就是在一致性和可用性之間取一個平衡。

        那為什麼說在P滿足的情況下,為什麼說CA不能同時滿足呢?我們來通過假設看一看,如果CA同時滿足會怎麼樣:

(1)假設現在要求滿足C(一致性),那麼就是說所有的節點在某一刻提供的資料都必須一致,我們知道在P的情況,是不可能保證的,要保證的話,就只能把其他節點全部幹掉,比如禁止讀寫,那這其實就是和A是相悖的(某些節點雖然延遲,但是節點本身可用)

(2)假設現在要求滿足A(可用性),那麼就是說只要節點本身沒什麼問題,就可以對外提供服務,哪怕有點資料延遲,很明顯這肯定是和C相悖的。

 2、一致性的類別:

        CAP 是分散式事務處理的理論基礎,在分散式事務的最終解決方案中一般選擇犧牲一致性來換取可用性和分割區容錯性,但這裡的 「犧牲一致性」 並不是完全放棄資料的一致性,而是放棄強一致性而換取弱一致性。一致性一般可以分為以下三種:

(1)強一致性:在任意時刻,所有節點中的資料是一樣的,系統中的某個資料被成功更新後,後續任何對該資料的讀取操作都將得到更新後的值。比如傳統資料庫的事務特性 ACID,就是追求強一致性模型。

一個叢集需要對外部提供強一致性,就務必會損耗可用性,只要叢集內部某一臺伺服器的資料發生了改變,那麼就需要等待叢集內其他伺服器的資料同步完成後,才能正常的對外提供服務。

(2)弱一致性:系統中的某個資料被更新後,後續對該資料的讀取操作可能得到更新後的值,也可能是更改前的值,但即使過了不一致時間視窗後,後續對該資料的讀取也不一定是最新值。

(3)最終一致性:是弱一致性的特殊形式,雖然不保證在任意時刻任意節點上的同一份資料都是相同的,但經過一段時間後,所有服務節點間的資料最終會達到一致的狀態

弱一致性即使過了不一致時間視窗,後續的讀取也不一定能保證一致,而最終一致性過了不一致視窗後,後續的讀取一定保證一致。

3、什麼是 BASE 理論:

        BASE 理論是指,Basically Available(基本可用)、Soft-state( 軟狀態)、Eventual Consistency(最終一致性),是基於CAP定理演化而來,是對CAP中一致性和可用性權衡的結果。核心思想是即使無法做到強一致性,但每個業務根據自身的特點,採用適當的方式來使系統達到最終一致性。

  • BA 基本可用:指分散式系統在出現故障的時候,允許損失部分可用性,保證核心可用。但不等價於不可用。比如:搜尋引擎0.5秒返回查詢結果,但由於故障,2秒響應查詢結果;網頁存取過大時,部分使用者提供降級服務等。

  • 軟狀態:軟狀態是指允許系統存在中間狀態,並且該中間狀態不會影響系統整體可用性,即允許系統在不同節點間副本同步的時候存在延時。

  • 最終一致性:系統中的所有資料副本經過一定時間後,最終能夠達到一致的狀態,不需要實時保證系統資料的強一致性。

        很多時候我們並不要求資料的強一致性,而 BASE 通過犧牲強一致性來獲得更好的可用性,所以 BASE 理論的適用性更廣泛,比如更適合面向的是大型高可用可延伸的分散式系統

柔性事務和剛性事務:柔性事務滿足BASE理論(基本可用,最終一致),剛性事務滿足ACID理論。

二、一致性協定:

1、Gossip協定:

參考文章:https://juejin.cn/post/7023918632216297479

        叢集往往是由多個節點共同組成的,當一個節點加入叢集或者一個節點從叢集中下線的時候,都需要讓叢集中其他的節點知道,這樣才能將資料資訊分享給新節點而忽略下線節點。

         如上圖,A、B、C 節點之間可以互相傳遞訊息,但是D節點在下線之後會被廣播告訴其他存活節點。這樣的廣播協定就是今天要說Gossip協定,Gossip協定也叫Epidemic協定(流行病協定),當一個訊息到來時,通過Gossip協定就可以像病毒一樣感染全部叢集節點。Gossip的過程是由一個種子節點發起的,當一個種子節點有資訊需要同步到網路中的其他節點時,它會隨機的選擇周圍幾個節點散播訊息,收到訊息的節點也會重複該過程,直至最終網路中所有的節點都收到了訊息。這個過程可能需要一定的時間,所以不能保證某個時間點所有的節點都有該條訊息,但是理論上最終所有節點都會收到訊息,因此它是一個最終一致性協定。

Gossip協定的特點:

  • (1)Gossip協定是週期性散播訊息,每隔一段時間傳播一次
  • (2)被感染的節點,每次可以繼續散播N個節點
  • (3)每次散播訊息時,都會選擇尚未傳送過的節點進行散播,不會向傳送的節點散播
  • (4)同一個節點可能會收到重複的訊息,因為可能同時多個節點正好向它散播
  • (5)叢集是去中心化的,節點之間都是平等的
  • (6)訊息的散播不用等接收節點的 ack,即訊息可能會丟失,但是最終應該會被感染

下面我們來看個例子:

  • ① 種子節點是A
  • ② A節點選擇B、C節點進行散播
  • ③ C散播到D,B散播D和E,可以發現D收到兩次
  • ④ D散播到F,最終整個網路都同步到了訊息

        Gossip有點類似圖的廣度優先遍歷演演算法,一般用於網路拓撲結構資訊的分享和維護,比如 Redis 叢集中節點的執行狀態就是使用 Gossip 協定進行傳遞的。

2、Raft一致性協定:

參考文章:https://baijiahao.baidu.com/s?id=1693824822611080380&wfr=spider&for=pc

        分散式協定的難點之一就是資料的一致性,當由多個節點組成的叢集中只有一個節點收到資料,我們就算成功的話,風險太大,當要求所有節點都收到資料才響應成功,效能又太差,所以一般會在資料的安全和效能之間做個折中,只要保證絕大部分節點同步資料成功,我們就算成功。比較知名的一致性演演算法有Raft演演算法,被廣泛應用於許多中介軟體中,接下來我們就看看Raft演演算法是實現分散式系統的不同節點間的資料一致性的,也就是說使用者端傳送請求到任何一個節點都能收到一致的返回,當一個節點出故障後,其他節點仍然能以已有的資料正常進行。

        首先介紹下在Raft演演算法中,幾種情況下每個節點對應的角色:

(1)Leader節點:同大多數分散式中的Leader節點一樣,所有資料的變更都需要先經過Leader

(2)Follower節點:Leader節點的追隨者,負責複製資料並且在選舉時候投票的節點

(3)Candidate候選節點:參與選舉的節點,就是Follower節點參與選舉時會切換的角色

Raft演演算法將一致性問題分解為兩個的子問題,Leader選舉 + 資料紀錄檔的複製:

2.1、Leader 選舉:

        系統在剛開始的時候,所有節點都是Follower節點,這時都有機會參與選舉,將自己變成Candidate,變成Candidate的節點會先投自己1票,同時告訴其它節點,讓它們來投票,當拿到超過半數以上的投票時,當前Candidate就會變成Leader節點。但是如果每個Follower節點都變成Candidate那麼就會陷入無限的死迴圈,於是每個Follower都一個定時器,並且定時器的時間是隨機的,當某個Follower的定時器時間走完之後,會確認當前是否存在Leader節點,如果不存在再把自己變成Candidate。

  • ① 由於A節點的定時器時間最短(10ms),所以A會成為Candidate。
  • ② A投自己一票,並告訴B、C來投票,B、C也投出自己的同意票後,A就會變成Leader節點,同時會記錄是第M任。這個M是做版本校驗的,比如一個編號是10的節點,收到了一個編號是9的節點的投票請求,那麼就會拒絕這個請求。

        在Leader節點選舉出來以後,Leader節點會不斷的傳送心跳給其它Follower節點證明自己是活著的,其他Follower節點在收到心跳後會清空自己的定時器,並回復給Leader,因為此時沒必要觸發選舉了。

        如果Leader節點在某一刻掛了,那麼Follower節點就不會收到心跳,因此在定時器到來時就會觸發新一輪的選舉,流程還是一樣。但是如果恰巧兩個Follower都變成了Candidate,並且都得到了同樣的票數,那麼此時就會陷入僵局,為了打破僵局,這時每個Candidate都會隨機推遲一段時間再次請求投票,當然一般情況下,就是先來先得,優先跑完定時器的Candidate理論成為Leader的概率更大。

        選舉流程大致如上,接下來我們來看看資料紀錄檔的複製。

2.2、資料紀錄檔的複製:

        當Leader節點收到使用者端Client的請求變更時,會把變更記錄到log中,然後Leader會將這個變更隨著下一次的心跳通知給Follower節點,收到訊息的Follower節點把變更同樣寫入紀錄檔中,然後回覆Leader節點,當Leader收到大多數的回覆後,就把變更寫入自己的儲存空間,同時回覆client,並告訴Follower應用此log。至此,叢集就變更達成了共識。

(1)正常情況下的紀錄檔複製:

  • ① 一開始,Leader 和兩個 Follower 都沒有任何資料。
  • ② 使用者端傳送請求給 Leader,儲存資料 「sally」,Leader 先將資料寫在本地紀錄檔,這時候資料狀態還是 Uncommitted (還沒最終確認,使用紅色表示)
  • ③ Leader 給兩個 Follower 節點傳送 AppendEntries 請求,資料在 Follower 上沒有衝突,則將資料暫時寫在本地紀錄檔,Follower 的資料也還是 Uncommitted
  • ④ Follower 將資料寫到本地後,返回 OK。Leader 收到後成功返回,只要收到的成功的返回數量超過半數 (包含Leader),Leader 將資料 「sally」 的狀態改成 Committed。( 這個時候 Leader 就可以返回給使用者端了)
  • ⑤ Leader 再次給 Follower 傳送 AppendEntries 請求,收到請求後,Follower 將本地紀錄檔裡 Uncommitted 資料改成 Committed。這樣就完成了整個複製紀錄檔的過程,三個節點的資料是一致的,

(2)Network Partition 網路分割區情況下紀錄檔複製:

        在 Network Partition 的情況下,部分節點之間沒辦法互相通訊,Raft 也能保證這種情況下資料的一致性

① 一開始有 5 個節點處於同一網路狀態下,如下圖:

 ② Network Partition 將節點分成兩邊,一邊有兩個節點,一邊三個節點:

 ③ 兩個節點這邊已經有 Leader 了,來自使用者端的資料 「bob」 通過 Leader 同步到 Follower。

 ④ 只有兩個節點,少於3個節點,所以 「bob」 的狀態仍是 Uncommitted。所以在這裡,伺服器會返回錯誤給使用者端

⑤ 另外一個 Partition 有三個節點,進行重新選主。

⑥ 使用者端資料 「tom」 發到新的 Leader2,並通過和上節網路狀態下相似的過程,同步到另外兩個 Follower;但因為這個 Partition 有3個節點,超過半數,所以資料 「tom」 都 Commit 了。

 ⑦ 網路狀態恢復,5個節點再次處於同一個網路狀態下。但是這裡出現了資料衝突 「bob" 和 「tom"

⑧ 三個節點的 Leader2 廣播 AppendEntries

 ⑨ 兩個節點 Partition 的 Leader 自動降級為 Follower,因為這個 Partition 的資料 「bob」 沒有 Commit,返回給使用者端的是錯誤,使用者端知道請求沒有成功,所以 Follower 在收到 AppendEntries 請求時,可以把 「bob「 刪除,然後同步 」tom」,通過這麼一個過程,就完成了在 Network Partition 情況下的複製紀錄檔,保證了資料的一致性。