分佈式理論系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab

分佈式理論系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab

本文介紹一致性算法: 2PC 到 3PC 到 Paxos 到 Raft 到 Zabnode

兩類一致性算法(操做原子性與副本一致性)算法

  • 2PC 3PC 協議用於保證屬於多個數據分片上的操做的原子性。這些數據分片可能分佈在不一樣的服務器上,2PC 協議保證多臺服務器上的操做要麼所有成功,要麼所有失敗。數據庫

  • Paxos Raft Zab 協議用於保證同一個數據分片的多個副本之間的數據一致性。當這些副本分佈到不一樣的數據中心時,這個需求尤爲強烈。segmentfault

1、2PC(阻塞、數據不一致問題、單點問題)

Two-Phase Commit(兩階段提交) 是計算機網絡尤爲是在數據庫領域內,爲了使基於分佈式系統架構下的全部節點在進行事務處理過程當中可以保持原子性和致性而設計的一種算法。一般,二階段提交協議也被認爲是一種一致性協議,用來保證分佈式系統數據的一致性。絕大部分的關係型數據庫都是採用二階段提交協議來完成分佈式事務處理。服務器

1.1 協議介紹

第一階段:提交事務請求(投票階段)

  1. 事務詢問網絡

    協調者向全部的參與者發送事務內容,詢問是否能夠執行事務提交操做,並開始等待各參與者的響應。架構

  2. 執行事務分佈式

    各參與者節點執行事務操做,並將 Undo 和 Redo 信息計入事務日誌中。ide

  3. 各參與者向協調者反饋事務詢問的響應性能

    若是參與者成功執行了事務操做,那麼就反饋給協調者 Yes 響應,表示事務能夠執行;若是參與者沒有成功執行事務,那麼就反饋給協調者 No 響應,表示事務不能夠執行。

第二階段:執行事務提交(執行階段)

(1)執行事務提交

執行事務提交

若是全部參與者的反饋都是 Yes 響應,那麼

  1. 發送提交請求

    協調者向全部參與者節點發出Commit請求

  2. 事務提交

    參與者接收到Commit請求後,會正式執行事務提交操做,並在完成提交以後釋放在整個事務執行期間佔用的事務資源

  3. 反饋事務提交結果

    參與者在完成事務提交以後,向協調者發送ACK信息

  4. 完成事務

    協調者接收到全部參與者反饋的ACK消息後,完成事務

(2)中斷事務

中斷事務

任何一個參與者反饋了 No 響應,或者在等待超時以後,協調者尚沒法接收到全部參與者的反饋響應,那麼就會中斷事務。

  1. 發送回滾請求

    協調者向全部參與者節點發出Rollback請求

  2. 事務回滾

    參與者接收到rollback請求後,會利用其在階段一中記錄的Undo信息來執行事務回滾操做,並在完成回滾以後釋放整個事務執行期間佔用的資源

  3. 反饋事務回滾結果

    參與者在完成事務回滾以後,向協調者發送ACK信息

  4. 中斷事務

    協調者接收到全部參與者反饋的ACK信息後,完成事務中斷

1.2 優缺點

優勢:原理簡單、實現方便

缺點:同步阻塞、單點問題、數據不一致、太過保守

(1)同步阻塞

同步阻塞會極大地限制分佈式系統的性能。在二階段提交的執行過程當中,全部參與該事務操做的邏輯都處於阻塞狀態,各個參與者在等待其餘參與者響應的過程當中,將沒法進行其餘任何操做。

(2)單點問題

一旦協調者出現問題,那麼整個二階段提交流程將沒法運轉,更爲嚴重的是,若是是在階段二中出現問題,那麼其餘參與者將會一直處於鎖定事務資源的狀態中,沒法繼續完成事務操做。

(3)數據不一致

在階段二,當協調者向全部參與者發送commit請求以後,發生了局部網絡異常或協調者在還沒有發完commit請求以前自身發生了崩潰,致使最終只有部分參與者接收到了commit請求,因而這部分參與者執行事務提交,而沒收到commit請求的參與者則沒法進行事務提交,因而整個分佈式系統出現了數據不一致性現象。

(4)太過保守

若是參與者在與協調者通訊期間出現故障,協調者只能靠超時機制來判斷是否須要中斷事務,這個策略比較保守,須要更爲完善的容錯機制,任意一個節點的失敗都會致使整個事務的失敗。

2、3PC(解決2PC的阻塞,但仍是可能形成數據不一致)

Three-Phase Commit,三階段提交,分爲 CanCommit、PreCommit、doCommit 三個階段。

3PC

2.1 協議介紹

爲了不在通知全部參與者提交事務時,其中一個參與者 crash 不一致時,就出現了三階段提交的方式。三階段提交在兩階段提交的基礎上增長了一個 preCommit 的過程,當全部參與者收到 preCommit 後,並不執行動做,直到收到 commit 或超過必定時間後才完成操做。

第一階段: CanCommit

  1. 事務詢問
    協調者向各參與者發送 CanCommit 的請求,詢問是否能夠執行事務提交操做,並開始等待各參與者的響應

  2. 參與者向協調者反饋詢問的響應
    參與者收到 CanCommit 請求後,正常狀況下,若是自身認爲能夠順利執行事務,那麼會反饋 Yes 響應,並進入預備狀態,不然反饋 No。

第二階段: PreCommit

(1)執行事務預提交

若是協調者接收到各參與者反饋都是 Yes,那麼執行事務預提交

  1. 發送預提交請求
    協調者向各參與者發送 preCommit 請求,並進入 prepared 階段

  2. 事務預提交
    參與者接收到 preCommit 請求後,會執行事務操做,並將Undo和Redo信息記錄到事務日記中

  3. 各參與者向協調者反饋事務執行的響應
    若是各參與者都成功執行了事務操做,那麼反饋給協調者 Ack 響應,同時等待最終指令,提交 commit 或者終止 abort

(2)中斷事務

若是任何一個參與者向協調者反饋了No響應,或者在等待超時後,協調者沒法接收到全部參與者的反饋,那麼就會中斷事務。

  1. 發送中斷請求
    協調者向全部參與者發送 abort 請求

  2. 中斷事務
    不管是收到來自協調者的 abort 請求,仍是等待超時,參與者都中斷事務

第三階段: doCommit

(1)執行提交

  1. 發送提交請求
    假設協調者正常工做,接收到了全部參與者的ack響應,那麼它將從預提交階段進入提交狀態,並向全部參與者發送doCommit請求

  2. 事務提交
    參與者收到doCommit請求後,正式提交事務,並在完成事務提交後釋放佔用的資源

  3. 反饋事務提交結果
    參與者完成事務提交後,向協調者發送ACK信息

  4. 完成事務
    協調者接收到全部參與者ack信息,完成事務

(2)中斷事務

假設協調者正常工做,而且有任一參與者反饋No,或者在等待超時後沒法接收全部參與者的反饋,都會中斷事務

  1. 發送中斷請求
    協調者向全部參與者節點發送abort請求

  2. 事務回滾
    參與者接收到 abort 請求後,利用 undo 日誌執行事務回滾,並在完成事務回滾後釋放佔用的資源

  3. 反饋事務回滾結果
    參與者在完成事務回滾以後,向協調者發送 ack 信息

  4. 中斷事務
    協調者接收到全部參與者反饋的 ack 信息後,中斷事務。

階段三可能出現的問題:

協調者出現問題、協調者與參與者之間網絡出現故障。不論出現哪一種狀況,最終都會致使參與者沒法及時接收到來自協調者的 doCommit 或是 abort 請求,針對這種狀況,參與者都會在等待超時後,繼續進行事務提交(timeout 後中斷事務)。

2.2 優缺點

優勢:下降參與者阻塞範圍,並可以在出現單點故障後繼續達成一致
缺點:引入 preCommit 階段,在這個階段若是出現網絡分區,協調者沒法與參與者正常通訊,參與者依然會進行事務提交,形成數據不一致。

3、Paxos(解決單點問題)

Paxos 算法目的是讓整個集羣的結點對某個值的變動達成一致。Paxos 算法(強一致性算法)屬於多數派——大多數的決定會成個整個集羣的統一決定。任何一個點均可以提出要修改某個數據的提案,是否經過這個提案取決於這個集羣中是否有超過半數的結點贊成(因此 Paxos 算法須要集羣中的結點是單數)

這個算法有兩個大階段,四個小階段(Paxos 有 Proposer 和 Acceptor 兩個角色)

  1. Prepare proposer 提出一個提案,編號爲 N ,此 N 大於這個 proposer 以前提出提案編號。請求 acceptors 的 quorum 接受。
  2. Promise 若是 N 大於此 acceptor 以前接受的任何提案編號則接受,不然拒絕
  3. Accept 若是達到了多數派, Proposer 會發出 accept 請求,此請求包含提案編號 N,以及提案內容
  4. Accepted 若是此 acceptor 在此期間沒有收到任何編號大於 N 的提案,則接受此提案內容,不然忽略

Paxos 四個階段

下面詳細解釋一下這四個階段(A 爲 Proposer, A、B、C 均爲 Acceptor)

第一階段:Prepare 階段

A 把申請修改的請求 Prepare Request 發給全部的結點 A,B,C。注意,Paxos 算法會有一個 Sequence Number(你能夠認爲是一個提案號,這個數不斷遞增,並且是惟一的,也就是說 A 和 B 不可能有相同的提案號),這個提案號會和修改請求一同發出,任何結點在 「Prepare 階段」 時都會拒絕其值小於當前提案號的請求。因此,結點 A 在向全部結點申請修改請求的時候,須要帶一個提案號,越新的提案,這個提案號就越是是最大的。

若是接收結點收到的提案號 n 大於其它結點發過來的提案號,這個結點會迴應 Yes(本結點上最新的被批准提案號),並保證不接收其它 <n 的提案。這樣一來,結點上在 Prepare 階段里老是會對最新的提案作承諾。

優化:在上述 prepare 過程當中,若是任何一個結點發現存在一個更高編號的提案,則須要通知提案人,提醒其中斷此次提案。

第二階段:Accept 階段

若是提案者 A 收到了超過半數的結點返回的 Yes,而後他就會向全部的結點發布 Accept Request(一樣,須要帶上提案號 n),若是沒有超過半數的話,那就返回失敗。

當結點們收到了 Accept Request 後,若是對於接收的結點來講,n 是最大的了,那麼,它就會經過 request(修改這個值),若是發現本身有一個更大的提案號,那麼,結點就會拒絕 request(拒絕修改)。

咱們能夠看以,這彷佛就是一個「兩段提交」的優化。其實,2PC/3PC 都是分佈式一致性算法的殘次版本,Google Chubby 的做者 Mike Burrows 說過這個世界上只有一種一致性算法,那就是 Paxos,其它的算法都是殘次品。

咱們還能夠看到:對於同一個值的在不一樣結點的修改提案就算是在接收方被亂序收到也是沒有問題的。

4、Raft(解決 Paxos 的實現難度)

Raft 是簡化版的 Paxos。Raft 劃分紅三個子問題:一是Leader Election;二是 Log Replication;三是 Safety。Raft 定義了三種角色 Leader、Follower、Candidate,最開始你們都是 Follower,當 Follower 監聽不到 Leader,就能夠本身成爲 Candidate,發起投票。

4.1 Leader 選舉:timeout 限制

每一個 Follower 都在 150ms and 300ms 之間隨機超時,以後看誰先 timeout,誰就先成爲 Candidate,而後它會先投本身一票,再向其餘節點發起投票邀請。若是其餘節點在這輪選舉尚未投過票,那麼就給 Candidate 投票,而後重置本身的選舉 timeout。若是獲得大多數的投票就成爲 Leader,以後按期開始向 Follower 發送心跳。

若是兩個 Follower 同時成爲 Candidate 的話,若是最後獲得的票數相同,則等待其餘 Follower 的選擇 timeout 以後成爲 Candidate,繼續開始新一輪的選舉。

4.2 log複製

Leader 把變更的 log 藉助心跳同步給 Follower,過半回覆以後才成功提交,以後再下一次心跳以後,Follower 也 commit 變更,在本身的 node 上生效。

分裂以後,另外一個分區的 Follower 接受不到 Leader 的 timeout,而後會有一個先 timeout,成爲 Candidate,最後成爲 Leader。因而兩個分區就有了兩個 Leader。

當客戶端有變更時,其中的 Leader 因爲沒法收到過半的提交,則保持未提交狀態。有的 Leader 的修改,能夠獲得過半的提交,則能夠修改生效。

當分裂恢復以後,Leader 開始對比選舉的 term,發現有更高的 term 存在時,他們會撤銷未提交的修改,而後以最新的爲準。

5、ZAB

基本與 raft 相同。在一些名詞的叫法上有些區別,如 ZAB 將某一個 Leader 的週期稱爲 epoch,而 raft 則稱之爲 term。實現上也有些許不一樣,如 raft 保證日誌連續性,心跳方向爲 Leader 至 Follower,ZAB 則相反。

參考:

  1. 《分佈式理論系列》:http://www.javashuo.com/article/p-qeojaqpe-kq.html
  2. 從 Paxos 到 Zookeeper : 分佈式一致性原理與實踐
  3. 《一致性算法(Paxos、Raft、ZAB)視頻》:https://www.bilibili.com/video/av21667358/
  4. 《分佈式事務中2PC與3PC的區別》:https://blog.csdn.net/yyd19921214/article/details/68953629

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索