分佈式技術架構原理解析之協調與同步(四)分佈式事務

概述

通常我們在網上商城購物,對於每一筆訂單交易來說,一般會有兩個核心的步驟:

  • 訂單業務:下訂單操作
  • 庫存業務:減庫存操作
    訂單業務和庫存業務一般會運行在不同的機器上,甚至是運行在不同區域的機器上。針對同一筆訂單,當且僅當訂單操作和減庫存操作一致時,才能保證交易的正確性。也就是說一筆訂單,只有這兩個操作都完成,才能算做處理成功,否則處理失敗,在分佈式領域中,這個問題就是分佈式事務問題。

1、什麼是分佈式事務

事務,其實是包含一系列操作的、一個有邊界的工作序列,有明確的開始和結束標誌,且要麼被完全執行,要麼完全失敗,即 all or nothing。通常情況下,我們所說的事務指的都是本地事務,也就是在單機上的事務。
事務的特徵 ACID,也是分佈式事務的基本特徵,其中 ACID 具體含義如下:

  • 原子性(Atomicity),即事務最終的狀態只有兩種,全部執行成功和全部不執行。若處理事務的任何一項操作不成功,就會導致整個事務失敗。一旦操作失敗,所有操作都會被取消(即回滾),使得事務彷彿沒有被執行過一樣。
  • 一致性(Consistency),是指事務操作前和操作後,數據的完整性保持一致或滿足完整性約束。比如,用戶 A 和用戶 B 在銀行分別有 800 元和 600 元,總共 1400 元,用戶 A 給用戶 B 轉賬 200 元,分爲兩個步驟,從 A 的賬戶扣除 200 元和對 B 的賬戶增加 200 元 ; 一致性就是要求上述步驟操作後,最後的結果是用戶 A 還有 600 元,用戶 B 有 800 元,總共 1400 元,而不會出現用戶 A 扣除了 200 元,但用戶 B 未增加的情況。
  • 隔離性(Isolation),是指當系統內有多個事務併發執行時,多個事務不會相互干擾,即一個事務內部的操作及使用的數據,對其他併發事務是隔離的。
  • 持久性(Durability),也被稱爲永久性,是指一個事務完成了,那麼它對數據庫所做的更新就被永久保存下來了。即使發生系統崩潰或宕機等故障,只要數據庫能夠重新被訪問,那麼一定能夠將其恢復到事務完成時的狀態。
    分佈式事務,就是在分佈式系統中運行的事務,由多個本地事務組合而成。基本能夠滿足 ACID,其中的 C 是強一致性,也就是所有操作均執行成功,才提交最終結果,以保證數據一致性或完整性。但隨着分佈式系統規模不斷擴大,複雜度急劇上升,達成強一致性所需時間週期較長,限定了複雜業務的處理。爲了適應複雜業務,出現了 BASE 理論,該理論的一個關鍵點就是採用最終一致性代替強一致性。
    BASE 理論包括基本可用(Basically Available)、柔性狀態(Soft State)和最終一致性(Eventual Consistency)。
  • 基本可用:分佈式系統出現故障的時候,允許損失一部分功能的可用性。
  • 柔性狀態:在柔性事務中,允許系統存在中間狀態,且這個中間狀態不會影響系統整體可用性。比如,數據庫讀寫分離,寫庫同步到讀庫(主庫同步到從庫)會有一個延時,其實就是一種柔性狀態。
  • 最終一致性:事務在操作過程中可能會由於同步延遲等問題導致不一致,但最終狀態下,數據都是一致的。
    可見,BASE 理論爲了支持大型分佈式系統,通過犧牲強一致性,保證最終一致性,來獲得高可用性,是對 ACID 原則的弱化。

2、分佈式事務實現

分佈式事務主要是解決在分佈式環境下,組合事務的一致性問題。實現分佈式事務有以下 3 種基本方法

  • 基於 XA 協議的二階段提交協議方法:強一致性
  • 三階段提交協議方法:強一致性
  • 基於消息的最終一致性方法:最終一致性

2.1基於 XA 協議的二階段提交方法

2.1.1 XA 協議的二階段提交方法

XA 是一個分佈式事務協議,規定了事務管理器和資源管理器接口。可以分爲兩部分,即事務管理器和本地資源管理器。
其中事務管理器作爲協調者,負責各個本地資源的提交和回滾;而資源管理器就是分佈式事務的參與者,通常由數據庫實現,比如 Oracle、DB2 等商業數據庫都實現了 XA 接口。
基於 XA 協議的二階段提交方法中,二階段提交協議(The two-phase commit protocol,2PC),用於保證分佈式系統中事務提交時的數據一致性,是 XA 在全局事務中用於協調多個資源的機制。

2.1.2 實現過程

通過兩階段提交協議來保證分佈式系統在不同節點上的分佈式事務的一致性,需要引入一個協調者來管理所有的節點,並確保這些節點正確提交操作結果,若提交失敗則放棄事務。
兩階段提交協議的具體過程分爲投票(voting)和提交(commit)兩個階段。

  • 第一階段投票:協調者(Coordinator,即事務管理器)會向事務的參與者(Cohort,即本地資源管理器)發起執行操作的 CanCommit 請求,並等待參與者的響應。參與者接收到請求後,會執行請求中的事務操作,記錄日誌信息但不提交,待參與者執行成功,則向協調者發送“Yes”消息,表示同意操作;若不成功,則發送“No”消息,表示終止操作。

  • 第二階段,提交:當所有的參與者都返回了操作結果(Yes 或 No 消息)後系統進入了提交階段,在提交階段,協調者會根據所有參與者返回的信息向參與者發送 DoCommit 或 DoAbort 指令:

  • 若協調者收到的都是“Yes”消息,則向參與者發送“DoCommit”消息,參與者會完成剩餘的操作並釋放資源,然後向協調者返回“HaveCommitted”消息;

  • 如果協調者收到的消息中包含“No”消息,則向所有參與者發送“DoAbort”消息,此時發送“Yes”的參與者則會根據之前執行操作時的回滾日誌對操作進行回滾,然後所有參與者會向協調者發送“HaveCommitted”消息;

  • 協調者接收到“HaveCommitted”消息,就意味着整個事務結束了
    二階段提交的算法思路可以概括爲協調者下發請求事務操作,參與者將操作結果通知協調者,協調者根據所有參與者的反饋結果決定各參與者是要提交操作還是撤銷操作

2.1.3 二階段提交算法的不足

  • 同步阻塞問題:二階段提交算法在執行過程中,所有參與節點都是事務阻塞型的。也就是說,當本地資源管理器佔有臨界資源時,其他資源管理器如果要訪問同一臨界資源,會處於阻塞狀態。
  • 單點故障問題:基於 XA 的二階段提交算法類似於集中式算法,一旦事務管理器發生故障,整個系統都處於停滯狀態。尤其是在提交階段,一旦事務管理器發生故障,資源管理器會由於等待管理器的消息,而一直鎖定事務資源,導致整個系統被阻塞。
  • 數據一致性問題:在提交階段,當協調者向參與者發送 DoCommit 請求之後,如果發生了局部網絡異常,或者在發送提交請求的過程中協調者發生了故障,就會導致只有一部分參與者接收到了提交請求並執行提交操作,但其他未接到提交請求的那部分參與者則無法執行事務提交。於是整個分佈式系統便出現了數據不一致的問題。

2.2三階段提交方法

2.2.1 三階段提交方法

三階段提交協議(Three-phase commit protocol,3PC),解決了兩階段提交的同步阻塞和數據不一致問題,三階段提交引入了超時機制和準備階段。

  • 同時在協調者和參與者中引入超時機制。如果協調者或參與者在規定的時間內沒有接收到來自其他節點的響應,就會根據當前的狀態選擇提交或者終止整個事務。
  • 在第一階段和第二階段中間引入了一個準備階段,也就是在提交階段之前,加入了一個預提交階段。在預提交階段排除一些不一致的情況,保證在最後提交之前各參與節點的狀態是一致的。

2.2.2 三階段提交方法實現過程

除了引入超時機制之外,3PC 把 2PC 的提交階段一分爲二,這樣三階段提交協議就有 CanCommitPreCommitDoCommit 三個階段:
第一階段:CanCommit 階段

  • 協調者向參與者發送請求操作(CanCommit 請求),詢問參與者是否可以執行事務提交操作,然後等待參與者的響應;
  • 參與者收到 CanCommit 請求之後,回覆 Yes,表示可以順利執行事務;
  • 否則回覆 No。
    CanCommit 階段不同節點之間的事務請求成功和失敗的流程,如下所示:
    在這裏插入圖片描述
    第二階段: PreCommit 階段
    協調者根據參與者的回覆情況,來決定是否可以進行PreCommit 操作。
    1.如果所有參與者回覆的都是“Yes”,那麼協調者就會執行事務的預執行:
  • 發送預提交請求:協調者向參與者發送 PreCommit 請求,進入預提交階段。
  • 事務預提交:參與者接收到 PreCommit 請求後執行事務操作,並將 Undo 和 Redo 信息記錄到事務日誌中。
  • 響應反饋:如果參與者成功執行了事務操作,則返回 ACK 響應,同時開始等待最終指令。
    2.假如任何一個參與者向協調者發送了“No”消息,或者等待超時之後,協調者都沒有收到參與者的響應,就執行中斷事務的操作:
  • 發送中斷請求:協調者向所有參與者發送“Abort”消息。
  • 中斷事務:參與者收到“Abort”消息之後,或超時後仍未收到協調者的消息,執行事務的中斷操作。
    預執行階段,不同節點上事務執行成功和失敗的流程,如下所示:
    在這裏插入圖片描述
    第三階段:DoCommit 階段
    DoCmmit 階段進行真正的事務提交,根據 PreCommit 階段協調者發送的消息,進入執行提交階段或事務中斷階段。
    1.執行提交階段
  • 發送提交請求:協調者接收到所有參與者發送的 Ack 響應,從預提交狀態進入到提交狀態,並向所有參與者發送 DoCommit消息。
  • 事務提交:參與者接收到 DoCommit消息之後,正式提交事務。完成事務提交之後,釋放所有鎖住的資源。
  • 響應反饋:參與者提交完事務之後,向協調者發送 Ack響應。
  • 完成事務:協調者接收到所有參與者的 Ack 響應之後,完成事務。
    2.事務中斷階段
  • 發送中斷請求:協調者向所有參與者發送 Abort 請求。
  • 事務回滾:參與者接收到 Abort 消息之後,利用其在 PreCommit階段記錄的 Undo 信息執行事務的回滾操作,並釋放所有鎖住的資源。
  • 反饋結果:參與者完成事務回滾之後,向協調者發送 Ack消息。
  • 中斷事務:協調者接收到參與者反饋的 Ack 消息之後,執行事務的中斷,並結束事務。
    執行階段不同節點上事務執行成功和失敗 (事務中斷) 的流程,如下所示:
    在這裏插入圖片描述

2.2.3 三階段提交方法小結

當參與者向協調者發送 Ack 消息後,如果長時間沒有得到協調者的響應,在默認情況下,參與者會自動將超時的事務進行提交,不會像兩階段提交那樣被阻塞住
但是,2PC 和 3PC 這兩種方法,有兩個共同的缺點,一是都需要鎖定資源,降低系統性能;二是,沒有解決數據不一致的問題。

2.3 基於分佈式消息的最終一致性方案

由於二段和三段都沒有解決一致性的問題,所以有了分佈式消息來確保事務最終一致性的方案。
在分佈式系統架構中,解決一致性問題的核心思想就是:需要將分佈式處理的事務通過消息或者日誌的方式異步執行,消息或日誌可以存到本地文件、數據庫或消息隊列中,再通過業務規則進行失敗重試。這個就是使用基於分佈式消息的最終一致性方案解決了分佈式事務的問題,其引入了一個消息中間件(Message Queue,MQ),用於在多個應用之間進行消息傳遞。
基於消息中間件協商多個節點分佈式事務執行操作的示意圖,如下所示。
在這裏插入圖片描述
以網上購物爲例,根據基於分佈式消息的最終一致性方案,用戶 A 通過終端手機首先在訂單系統上操作,然後整個購物的流程如下所示:
在這裏插入圖片描述

2.4 三種分佈式事務實現方式對比

在這裏插入圖片描述

3 總結

在這裏插入圖片描述

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