分佈式一致性協議之2PC和3PC

因爲分佈式系統的各個服務可能分佈在不一樣的節點上,若是各節點直接沒有相互的通訊獲取其餘節點狀態,那麼各個節點是沒法知道其餘節點的任務處理結果的。算法

若是在分佈式系統中發起一個事務,該事務涉及多個不一樣節點,那麼爲了保證事務 ACID 特性,就須要引入一個協調者來統一調度事務涉及的多個節點,被調度的節點稱爲事務參與者。由此衍生出 2PC 和 3PC 協議,本文就來詳細介紹 2PC 和 3PC 的工做機制。數據庫

2PC(兩階段提交,Two-Phase Commit)

顧名思義,分爲兩個階段:Prepare 和 Commit網絡

Prepare:提交事務請求

基本流程以下圖:架構

2PC1.png

  1. 詢問 協調者向全部參與者發送事務請求,詢問是否可執行事務操做,而後等待各個參與者的響應。app

  2. 執行 各個參與者接收到協調者事務請求後,執行事務操做(例如更新一個關係型數據庫表中的記錄),並將 Undo 和 Redo 信息記錄事務日誌中。分佈式

  3. 響應 若是參與者成功執行了事務並寫入 Undo 和 Redo 信息,則向協調者返回 YES 響應,不然返回 NO 響應。固然,參與者也可能宕機,從而不會返回響應。設計

Commit:執行事務提交

執行事務提交分爲兩種狀況,正常提交和回退。3d

正常提交事務

流程以下圖:日誌

2PC2.png

  1. commit 請求 協調者向全部參與者發送 Commit 請求。cdn

  2. 事務提交 參與者收到 Commit 請求後,執行事務提交,提交完成後釋放事務執行期佔用的全部資源。

  3. 反饋結果 參與者執行事務提交後向協調者發送 Ack 響應。

  4. 完成事務 接收到全部參與者的 Ack 響應後,完成事務提交。

中斷事務

在執行 Prepare 步驟過程當中,若是某些參與者執行事務失敗、宕機或與協調者之間的網絡中斷,那麼協調者就沒法收到全部參與者的 YES 響應,或者某個參與者返回了 No 響應,此時,協調者就會進入回退流程,對事務進行回退。流程以下圖紅色部分(將 Commit 請求替換爲紅色的 Rollback 請求):

2PC4.png

  1. rollback 請求 協調者向全部參與者發送 Rollback 請求。

  2. 事務回滾 參與者收到 Rollback 後,使用 Prepare 階段的 Undo 日誌執行事務回滾,完成後釋放事務執行期佔用的全部資源。

  3. 反饋結果 參與者執行事務回滾後向協調者發送 Ack 響應。

  4. 中斷事務 接收到全部參與者的 Ack 響應後,完成事務中斷。

2PC 的問題

  1. 同步阻塞 參與者在等待協調者的指令時,實際上是在等待其餘參與者的響應,在此過程當中,參與者是沒法進行其餘操做的,也就是阻塞了其運行。 假若參與者與協調者之間網絡異常致使參與者一直收不到協調者信息,那麼會致使參與者一直阻塞下去。

  2. 單點 在 2PC 中,一切請求都來自協調者,因此協調者的地位是相當重要的,若是協調者宕機,那麼就會使參與者一直阻塞並一直佔用事務資源。

    若是協調者也是分佈式,使用選主方式提供服務,那麼在一個協調者掛掉後,能夠選取另外一個協調者繼續後續的服務,能夠解決單點問題。可是,新協調者沒法知道上一個事務的所有狀態信息(例如已等待 Prepare 響應的時長等),因此也沒法順利處理上一個事務。

  3. 數據不一致 Commit 事務過程當中 Commit 請求/Rollback 請求可能由於協調者宕機或協調者與參與者網絡問題丟失,那麼就致使了部分參與者沒有收到 Commit/Rollback 請求,而其餘參與者則正常收到執行了 Commit/Rollback 操做,沒有收到請求的參與者則繼續阻塞。這時,參與者之間的數據就再也不一致了。

    當參與者執行 Commit/Rollback 後會向協調者發送 Ack,然而協調者不管是否收到全部的參與者的 Ack,該事務也不會再有其餘補救措施了,協調者能作的也就是等待超時後像事務發起者返回一個「我不肯定該事務是否成功」。

  4. 環境可靠性依賴 協調者 Prepare 請求發出後,等待響應,然而若是有參與者宕機或與協調者之間的網絡中斷,都會致使協調者沒法收到全部參與者的響應,那麼在 2PC 中,協調者會等待必定時間,而後超時後,會觸發事務中斷,在這個過程當中,協調者和全部其餘參與者都是出於阻塞的。這種機制對網絡問題常見的現實環境來講太苛刻了。

3PC(三階段提交,Three-Phase Commit)

上面說明了 2PC 協議的多個缺點,那麼 3PC 就是在 2PC 的基礎上,爲了解決 2PC 的某些缺點而設計的,3PC 分爲三個階段:CanCommit,PreCommit 和 doCommit。

CanCommit

流程以下圖:

3PC1.png

  1. 事務詢問 協調者向全部參與者發送事務 canCommit 請求,請求中包含事務內容,詢問是否能夠執行事務提交操做,並開始等待響應。

  2. 反饋詢問結果 參與者收到 canCommit 請求後,分析事務內容,判斷自身是否能夠執行事務,若是能夠,那麼就返回 Yes 響應,進入預備狀態,不然返回 No 響應。

    注意:此過程當中並無執行事務(對比 2PC 的 Prepare 階段,參與者是執行了事務的)。

PreCommit

流程圖以下:

3PC2.png

PreCommit 階段根據各參與者返回的 CanCommit 響應,決定下一步動做。若是收到了全部參與者的 Yes 響應,則執行事務預提交,不然(收到了至少一個 No 響應或必定時長內沒有收到全部參與者的 Yes 響應,如 3PC 第一張圖片中紅色部分),執行事務中斷。

事務預提交

  1. 發送 PreCommit 請求 協調者發送 PreCommit 請求,並進入 Prepared 階段。

  2. 參與者處理 PreCommit 參與者收到 PreCommit 請求後,執行事務操做,並將 Undo 和 Redo 信息記錄事務日誌中。

  3. 反饋執行結果 若是參與者成功執行了事務並寫入 Undo 和 Redo 信息,那麼反饋 Ack 給協調者,並等待下一步指令。

事務中斷

上圖中,紅色的 Abort 表示協調者發送的不是 PreCommit 請求,而是 Abort 請求。

  1. 發送事務中斷請求 協調者向全部參與者發送 Abort 請求。

  2. 中斷事務 參與者收到 Abort 請求後,會觸發事務中斷。此外,若是參與者在等待協調者指令超時,會本身觸發事務中斷,在 2PC 中,參與者會一直阻塞的等待協調者指令,因此 3PC 中解決了由於這種狀況帶來的阻塞。

doCommit

流程圖以下:

3PC3.png

協調者根據第二階段的響應決定最終操做,若是協調者收到了全部參與者在 PreCommit 階段的 Ack 響應,那麼會進入執行事務提交階段,不然執行事務中斷。

事務提交

  1. 發送提交請求 協調者收到全部參與者在 PreCommit 階段返回的 Ack 響應後,向全部參與者發送 doCommit 請求,並進入提交狀態。

  2. 事務提交 參與者收到 Commit 請求後,執行事務提交,提交完成後釋放事務執行期佔用的全部資源。

  3. 反饋結果 參與者完成事務提交以後,向協調者返回 Ack 響應。

  4. 完成事務 協調者收到全部參與者的 Ack 響應後,完成事務。

事務中斷

  1. 發送事務中斷請求 協調者向全部參與者發送 Abort 請求。

  2. 事務回滾 參與者收到 Abort 請求後,會使用第二階段記錄的 Undo 信息進行事務回滾,並在完成回滾後釋放全部事務資源。

    注意:由於第一階段並無任何參與者實際執行事務,因此在第二階段(PreCommit 階段)執行事務中斷,是不須要事務回滾的,也就不須要下面的反饋結果,直接中斷事務便可。

  3. 反饋回滾結果 參與者執行事務回滾後向協調者發送 Ack 響應。

  4. 中斷事務 協調者接收到全部參與者反饋的 Ack 響應後,完成事務中斷。

3PC 的改進和缺點

改進

  1. 下降了阻塞

    • 參與者返回 CanCommit 請求的響應後,等待第二階段指令,若等待超時,則自動 abort,下降了阻塞;

    • 參與者返回 PreCommit 請求的響應後,等待第三階段指令,若等待超時,則自動 commit 事務,也下降了阻塞;

  2. 解決單點故障問題

    • 參與者返回 CanCommit 請求的響應後,等待第二階段指令,若協調者宕機,等待超時後自動 abort,;

    • 參與者返回 PreCommit 請求的響應後,等待第三階段指令,若協調者宕機,等待超時後自動 commit 事務;

缺點

數據不一致問題仍然是存在的,好比第三階段協調者發出了 abort 請求,而後有些參與者沒有收到 abort,那麼就會自動 commit,形成數據不一致。

總結

從上面講述來看,2PC 和 3PC 都沒法完美解決分佈式數據一致性問題,雖然沒法保證事務的 ACID 特性,但兩階段的思想在不少實際架構中有這普遍應用,例如 JTA 事務以及一些數據庫的數據同步。

引用一句話,是 Google Chubby 做者說的:

「There is only one consensus protocol, and that’s Paxos」 – all other approaches are just broken versions of Paxos.」

Paxos 是蘭伯特提出的一個解決分佈式一致性的算法,後面再寫文講述其原理。

相關文章
相關標籤/搜索