分佈式事務一致性協議(二階段提交協議2PC,三階段提交協議3PC)

   如果一個操作涉及多個分佈式節點,爲了保證事務的ACID特性,需要引入一個“協調者”組件來統一調度所有分佈式節點的執行邏輯,這些被調度的分佈式節點被稱爲“參與者”。協調者負責調度參與者的行爲,並最終決定這些參與者是否真正地提交事務。

分佈式事務通常採用二階段提交協議(2PC),它是幾乎所有分佈式事務算法的基礎,後續的分佈式事務算法幾乎都由此改進而來。

(一)2PC:

   二階段提交(Two-phase Commit,簡稱2PC),是指爲了使基於分佈式系統架構下的所有節點在進行事務提交時保持一致性而設計的一種算法(Algorithm)。通常2PC也被稱爲是一種協議(Protocol)。

在此協議中,一個事務管理器(Transaction Manager,簡稱 TM,也被稱之爲“協調者”)協調 1 個或多個資源管理器(Resource Manager,簡稱 RM,也被稱之爲“參與者”)的活動,所有資源管理器(參與者)向事務管理器(協調者)彙報自身活動狀態,由事務管理器(協調者)根據各資源管理器(協調者)彙報的狀態(完成準備或準備失敗)來決定各資源管理器(協調者)是“提交”事務還是進行“回滾”操作。

因此,二階段提交的算法思路可以概括爲:參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。
在這裏插入圖片描述
所謂的兩個階段是指:第一階段:準備階段(投票階段)和第二階段:提交階段(執行階段)。

第一階段:

協調者通知各個參與者準備提交它們的事務分支。如果參與者判斷自己進行的工作可以被提交,那就對工作內容進行持久化,再給協調者肯定答覆;要是發生了其他情況,那給協調者的都是否定答覆。在發送了否定答覆並回滾了已經的工作後,參與者就可以丟棄這個事務分支信息。

以MySQL數據庫爲例,在第一階段,事務管理器(協調者)向所有涉及到的數據庫服務器(參與者)發出Prepare “準備提交"請求,數據庫(參與者)收到請求後執行數據修改和日誌記錄等處理,處理完成後只是把事務的狀態改成"可以提交”,然後把結果返回給事務管理器(協調者)。

第二階段:

協調者根據第一階段中各個參與者 Prepare的結果,決定是提交還是回滾事務。如果所有的參與者都Prepare成功,那麼協調者通知所有的參與者進行提交;如果有參與者Prepare失敗的話,則協調者通知所有參與者回滾自己的事務分支。

還是以MySQL數據庫爲例,如果第一階段中所有數據庫(參與者)都Prepare成功,那麼事務管理器(協調者)向數據庫服務器(參與者)發出"確認提交"請求,數據庫服務器(參與者)把事務的"可以提交"狀態改爲"提交完成"狀態,然後返回應答。如果在第一階段內有任何一個數據庫(參與者)的操作發生了錯誤,或者事務管理器(協調者)收不到某個數據庫(參與者)的迴應,則認爲事務失敗,回撤所有數據庫(參與者)的事務。數據庫服務器(參與者)收不到第二階段的確認提交請求,也會把"可以提交"的事務回撤。

2PC提交的優點是儘量保證了數據的強一致,但不是 100% 一致。但是2PC也有明顯的缺點:

  • 單點故障:由於協調者的重要性,一旦協調者發生故障,參與者會一直阻塞,尤其是在第二階段,協調者發生故障,那麼所有的參與者都處於鎖定事務資源的狀態中,而無法繼續完成事務操作。
  • 同步阻塞:由於所有節點在執行操作時都是同步阻塞的,當參與者佔有公共資源時,其他第三方節點訪問公共資源不得不處於阻塞狀態。
  • 數據不一致:在第二階段中,當協調者向參與者發送提交事務請求之後,發生了局部網絡異常或者在發送提交事務請求過程中協調者發生了故障,這會導致只有一部分參與者接收到了提交事務請求。而在這部分參與者接到提交事務請求之後就會執行提交事務操作。但是其他部分未接收到提交事務請求的參與者則無法提交事務。從而導致分佈式系統中的數據不一致。

二階段提交的問題:如果協調者在第二階段發送提交請求之後掛掉,而唯一接受到這條消息的參與者執行之後也掛掉了,即使協調者通過選舉協議產生了新的協調者並通知其他參與者進行提交或回滾操作的話,都可能會與這個已經執行的參與者執行的操作不一樣。

(三)3PC:

   三階段提交(Three-phase Commit,簡稱3PC),是爲解決2PC中的缺點而設計的。參考維基百科:https://en.wikipedia.org/wiki/Three-phasecommitprotocol。與兩階段提交不同的是,三階段提交是“非阻塞”協議。
在這裏插入圖片描述
對應於2PC,3PC有兩個改動點:

  • 1:引入超時機制。同時在協調者和參與者中都引入超時機制。
  • 2:在兩階段提交的第一階段與第二階段之間插入了一個準備階段,使得原先在兩階段提交中,參與者在投票之後,由於協調者發生崩潰或錯誤而導致參與者處於無法知曉是否提交或者中止的“不確定狀態”所產生的可能相當長的延時的問題得以解決。

第一階段CanCommit:

3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者發送Commit請求,參與者如果可以提交就返回Yes響應,否則返回No響應。

  • 1:事務詢問:協調者向參與者發送CanCommit請求。詢問是否可以執行事務提交操作。然後開始等待參與者的響應。
  • 2:響應反饋:參與者接到CanCommit請求之後,正常情況下,如果其自身認爲可以順利執行事務,則返回Yes響應,並進入預備狀態。否則反饋No。

第二階段PreCommit:

協調者根據參與者的反應情況來決定是否可以進行事務的PreCommit操作。根據響應情況,有以下兩種可能。

  • 假如協調者從所有的參與者獲得的反饋都是Yes響應,那麼就會執行事務的預執行。

    a) 發送預提交請求:協調者向參與者發送PreCommit請求,並進入Prepared階段。

    b) 事務預提交:參與者接收到PreCommit請求後,會執行事務操作,並將undo和redo信息記錄到事務日誌中。

    c) 響應反饋:如果參與者成功的執行了事務操作,則返回ACK響應,同時開始等待最終指令。

  • 假如有任何一個參與者向協調者發送了No響應,或者等待超時之後,協調者都沒有接到參與者的響應,那麼就執行事務的中斷。

    a) 發送中斷請求:協調者向所有參與者發送Abort請求。

    b) 中斷事務:參與者收到來自協調者的Abort請求之後(或超時之後,仍未收到協調者的請求),執行事務的中斷。

第三階段DoCommit:

該階段進行真正的事務提交,也可以分爲以下兩種情況。

  • Case 1:執行提交。

    a) 發送提交請求:協調者接收到參與者發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向所有參與者發送DoCommit請求。

    b) 事務提交:參與者接收到DoCommit請求之後,執行正式的事務提交。並在完成事務提交之後釋放所有事務資源。

    c) 響應反饋:事務提交完之後,向協調者發送ACK響應。

    d) 完成事務:協調者接收到所有參與者的ACK響應之後,完成事務。

  • Case 2:中斷事務。協調者沒有接收到參與者發送的ACK響應(可能是接受者發送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。

    a) 發送中斷請求:協調者向所有參與者發送Abort請求。

    b) 事務回滾:參與者接收到Abort請求之後,利用其在階段二記錄的undo信息來執行事務的回滾操作,並在完成回滾之後釋放所有的事務資源。

    c) 反饋結果:參與者完成事務回滾之後,向協調者發送ACK消息。

    d) 中斷事務:協調者接收到參與者反饋的ACK消息之後,執行事務的中斷。

在三階段提交中,如果在第三階段協調者發送提交請求之後掛掉,並且唯一的接受的參與者執行提交操作之後也掛掉了,這時協調者通過選舉協議產生了新的協調者。在二階段提交時存在的問題就是新的協調者不確定已經執行過事務的參與者是執行的提交事務還是中斷事務。但是在三階段提交時,肯定得到了第二階段的再次確認,那麼第二階段必然是已經正確的執行了事務操作,只等待提交事務了。所以新的協調者可以從第二階段中分析出應該執行的操作,進行提交或者中斷事務操作,這樣即使掛掉的參與者恢復過來,數據也是一致的。

所以,三階段提交解決了二階段提交中存在的由於協調者和參與者同時掛掉可能導致的數據一致性問題和單點故障問題,並減少阻塞。因爲一旦參與者無法及時收到來自協調者的信息之後,他會默認執行提交事務,而不會一直持有事務資源並處於阻塞狀態。

不過3PC也存在自身的問題:在提交階段如果發送的是中斷事務請求,但是由於網絡問題,導致部分參與者沒有接到請求。那麼參與者會在等待超時之後執行提交事務操作,這樣這些由於網絡問題導致提交事務的參與者的數據就與接受到中斷事務請求的參與者存在數據不一致的問題。所以無論是 2PC 還是 3PC 都不能保證分佈式系統中的數據 100% 一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章