分散式事務,強一致性方案有哪些?|分散式事務系列(二)

架構師修行手冊發表於2023-03-28

來源:後端開發技術


繼續分散式事務專題:本文講解的是強一致性解決方案XA、2PC、3PC。

接著上一篇文章,由於我們非常關注資料的一致性,所以總體來說按照一致性強弱的維度分類,解決分散式事務問題可以有以下方案:

  • 強一致性方案:XA協議,2PC(兩階段提交)、3PC(三階段提交)
  • 最終一致性方案:TCC,本地事務狀態表、本地訊息表、可靠訊息最終一致性、RocketMQ 事務訊息方案、最大努力通知方案,SAGA
  • 弱一致性方案:基於業務補償,定時任務對賬

本文我們講解強一致性方案:XA協議,2PC(兩階段提交)、3PC(三階段提交)。如果上一篇基礎內容還沒有讀,請移步。

分散式事務,強一致性方案有哪些?|分散式事務系列(二)

CAP、BASE理論真的很重要!|分散式事務系列(一)


XA 協議

因為在使用本地事務的過程中有資料褲引擎的保證,但是如果是多資料來源場景下就有了一致性問題,為此產生了全域性事務。全域性事務並不限定資料來源是一個還是多個,但是在分散式系統場景下我們都當作多資料來源的分散式事務來討論。

為了解決分散式事務的一致性問題、統一標準,1991 年X/Open組織(後來併入國際開放標準組織The Open Group )提出了一套名為X/Open XA(XA 是 eXtended Architecture 的縮寫)的處理事務架構,制定了標準化的模型和介面。它定義了全域性的事務管理器(Transaction Manager,用於協調全域性事務)和區域性的資源管理器(Resource Manager,用於驅動本地事務)之間的通訊介面。1994年國際開放標準組織The Open Group 在1994年定義了分散式事務處理模型 DTP(Distributed Transaction Processing Reference Model,X/Open XA),XA 協議成為事務模型事實上的標準。

在 XA 協議下有三種核心角色:

  • AP(Application Program):應用程式,指事物的發起者。
  • RM(Resource Managers):資源管理器,是分散式事務的參與者,管理共享資源,並提供訪問介面,供外部程式來訪問共享資源,比如資料庫、列印服務等,另外 RM 還應該具有事務提交或回滾的能力。
  • TM(Transaction Manager):事務管理器,是分散式事務的協調者,管理全域性事務,與每個RM進行通訊,協調事務的提交和回滾,並協助進行故障恢復,此角色也可以由發起者擔任。
分散式事務,強一致性方案有哪些?|分散式事務系列(二)

基於 XA 規範 Java 中實現了 JTA ,MySQL、Oracle 也都對其做了支援,XA約定了TM和RM之間雙向通訊的介面規範,能在一個TM和多個RM之間形成通訊橋樑,透過協調多個資料來源的一致動作,實現全域性事務的統一提交或者統一回滾。

在XA協議下如果我們想實現一個商城的下單、扣款、扣庫存功能,可以實現如下虛擬碼。

orderTransaction.begin();//訂單
balanceTransaction.begin();//餘額
warehouseTransaction.begin();//倉庫
try{
  order.submit();//下單
  balance.pay();//付款
  warehouse.decrease();//扣減庫存
  orderTransaction.commit();//訂單
 balanceTransaction.commit();//餘額
  //故障點
 warehouseTransaction.commit();//倉庫
}catch(Exception e){
  //無法回滾
  orderTransaction.rollback();//訂單
 balanceTransaction.rollback();//餘額
 warehouseTransaction.rollback();//倉庫
}

訂單、餘額、倉庫三個資料來源分別開啟事務,如果成功分別提交事務。但是這段邏輯有個很大的問題就是如果訂單、餘額事務提交成功,但是倉庫commit發生異常,為了保證一致性需要全部迴歸,但是由於訂單、餘額已提交所以無法回滾,發生了資料不一致場景。面對這種問題,XA協議選擇了兩階段提交(2PC)作為實現,從而在多個資料庫資源下保證 ACID 四個特性。

  • 準備階段(投票階段):協調者詢問事務的所有參與者是否準備好提交,參與者如果已經準備好提交則回覆 Prepared,否則回覆 Non-Prepared。對於MySQL來說,準備階段是在 Redo Log 中記錄全部事務提交操作所要做的內容,並且鎖定需要變更的資源,它與本地事務中真正提交的區別只是沒有執行 commit 命令。這意味著在做完資料持久化後並不立即釋放隔離性,即仍繼續持有鎖,維持資料對其他非事務內觀察者的隔離狀態。
  • 提交階段(執行階段):協調者如果在上一階段收到所有事務參與者回覆的 Prepared 訊息,則先自己在本地持久化事務狀態為 Commit,在此操作完成後向所有參與者傳送 Commit 指令,所有參與者立即執行提交操作;如果任意一個參與者回覆了 Non-Prepared 訊息,或任意一個參與者超時未回覆,協調者將自己的事務狀態持久化為 Abort 之後,向所有參與者傳送 Abort 指令,參與者立即執行回滾操作。對於資料庫來說,這個階段的提交操作應是很輕量的,僅僅是持久化一條 Commit 命令,通常能夠快速完成,只有收到 Abort 指令時,才需要根據 Undo Log 清理已提交的資料,這可能是相對重負載的操作。

關於兩階段的內容我們在這裡不做過多解釋,具體請看後面兩階段專題。

優缺點

由於 XA 使用兩階段提交,因此兩階段提交的優點和缺點通常適用於 XA。

優點:XA 允許跨多種異構技術的原子事務(不同型別資料來源、訊息中介軟體),解決了分散式事務的問題,而傳統資料庫事務僅限於單一資料庫。

缺點:準備階段會長時間持有資源,造成系統效能降低,並且協調者會有單點故障的問題。

總結

如果你看到這感覺暈暈乎乎,還是沒明白XA到底是個啥,那需要看一下這段總結。

XA 協議是一種用於處理分散式事務的協議,定義了TM、RM、應用程式集中模型和介面,大多數實現XA的都是一些關係型資料庫(包括MySQL,SQL Server、PostgreSQL 和Oracle)和訊息中介軟體(包括ActiveMQ,HornetQ,MSMQ和IBM MQ),Java 中的 JTA 也實現了 XA 規範介面。

兩階段提交(Two-Phase Commit,簡稱2PC)是XA協議中的一種實現方式。透過介面規範,應用程式訪問並使用RM的資源,並透過TM的事務介面(TX interface)定義需要執行的事務操作,然後 TM和 RM 會基於 XA 規範,執行二階段提交協議進行事務的提交/回滾。

兩階段提交 2PC

階段提交(Two-Phase Commit,簡稱2PC)是分散式事務處理中的一種演算法,是最為經典的分散式事務解決方案之一。用於確保在涉及多個節點(或程式)的事務中,所有節點要麼全部提交(commit),要麼全部回滾(rollback),從而保持資料的一致性。

為了協調分散式環境下的不同服務,它透過一箇中心協調器來協調多個參與者的事務。該協調器在第一階段(準備階段)詢問所有參與者是否可以提交事務,如果所有參與者都準備好了,則在第二階段(提交階段)通知所有參與者提交事務。

兩階段提交演算法是由Jim Gray和Andreas Reuter在1981年提出的,並在1983年發表了相關論文《事務處理:概念和技術》(Transaction Processing: Concepts and Techniques)中進行了詳細討論。這篇論文是分散式事務處理領域的經典著作之一,對於今天的分散式系統設計仍然具有重要的參考價值。

兩階段過程

兩階段指的是分散式事務的提交過程分為兩個階段,具體流程如下:

第一階段(投票階段):

  1. 協調者(Coordinator)向參與者(Participant)發出請求執行事務的訊息。
  2. 參與者執行事務,並將 Undo 和 Redo 資訊記錄在事務日誌中,但並不提交事務,也就是說此時資源已經被鎖定。
  3. 參與者向協調者傳送“投票”訊息,表示事務是否執行成功。如果參與者執行成功,則返回“同意(Agree)”訊息;如果參與者執行失敗,則返回“否決(Abort)”訊息。

第二階段(提交階段):

  1. 協調者收到所有參與者的投票資訊,如果所有參與者都返回“同意”訊息,則協調者向所有參與者傳送“提交(Commit)”訊息。
  2. 參與者收到“提交”訊息後,執行提交操作,並釋放在第一階段中申請的所有資源。
  3. 如果任何一個參與者返回“否決”訊息,協調者將向所有參與者傳送“回滾(Rollback)”訊息。
  4. 參與者收到“回滾”訊息後,執行回滾操作,並釋放在第一階段中申請的所有資源。
分散式事務,強一致性方案有哪些?|分散式事務系列(二)
分散式事務,強一致性方案有哪些?|分散式事務系列(二)

需要注意的是,兩階段提交協議有可能會存在“阻塞”的問題,也就是說,在第一階段中,如果有任何一個參與者無法響應,那麼協調者將一直等待,直到超時。在這種情況下,需要採取超時機制和其他最佳化手段來提高系統的可用性和效能。

因為它需要在所有兩階段的缺點是存在單點故障和阻塞問題。

前提條件

兩階段提交的成立是有前提條件的。

  • 必須假設網路短時間內可靠。即提交階段不會丟失訊息,同時也假設網路通訊在全過程都不會出現誤差,可以丟失訊息,但不會傳遞錯誤的訊息。兩段式提交中投票階段失敗了可以回滾,而提交階段失敗了無法改變已提交的結果,因而此階段耗時應儘可能短,這也是為了儘量控制網路風險的考慮。
  • 必須假設故障節點最終能夠恢復,不會永久性地處於失聯狀態。由於在準備階段已經寫入了完整的 Undo log,所以當失聯機器一旦恢復,就能夠從日誌中找出已準備妥當但並未提交的事務資料,並向協調者查詢該事務的狀態,確定下一步應該進行提交還是回滾操作。

兩階段的問題

雖然兩階段可以解決大部分場景下的事務的一致性問題,並且原理簡單,但是它存在以下一些缺點。

1.資源佔用導致同步阻塞問題:在第一階段投票之後,參與的事務的每個節點資源都被鎖定,並且在第二階段參與者等到協調者的響應才能繼續執行,事務時間越長資源佔用時間越長。並且如果協調者發生故障,參與者會一直等待其響應,這回導致整個系統的效能受到影響。

2.單點故障問題:在2PC中,協調者扮演著關鍵的角色,如果協調者發生故障,整個事務就會失敗。協調者等待參與者回覆時可以有超時機制,允許參與者當機,但參與者等待協調者指令時無法做超時處理,事務將長時間持續。因此,協調者成為了系統的單點故障,這會影響整個系統的可用性。

3.資料不一致問題:其實兩階段提交有個前提,就是網路狀況短時間內穩定,這樣可以保證第一階段投票完畢後第二個階段可以順利提交。並且必須假設因故障而下線的節點最終能當機恢復,在第一階段中可以有 Undo Log 可以保證。但是如果在第一階段之後,協調者向參與者傳送的提交請求丟失或者超時或者節點當機,那麼就會導致一些參與者已經提交了資料,而另外一些參與者卻沒有提交資料,從而導致資料不一致。

分散式事務,強一致性方案有哪些?|分散式事務系列(二)

4.可擴充套件性問題:在大規模分散式系統中,參與者數量可能會非常龐大,這會導致協調者需要維護大量的狀態資訊,從而影響系統的可擴充套件性。

三階段提交 3PC

三階段提交(Three-Phase Commit,簡稱3PC)是分散式事務處理中的一種演算法,是在兩階段提交(2PC)的基礎上進一步發展的,主要是為了解決2PC中存在的一些問題,比如資源佔用、同步阻塞、單點故障以及提交階段可能出現的資料不一致問題。

相對於2PC,3PC 有兩個變動的地方:

  • 將第一階段投票階段拆分為CanCommit和PreCommit階段:這樣的好處是可以預先在資源沒有鎖定的情況下檢查資源的可用情況,檢查透過後PreCommit階段再鎖定資源。如果CanCommit的檢查全部透過,這樣後續成功的機率也會提高了。
  • 引入了超時機制:之前只有參與者可以超時,在3PC中協調者和參與者都引入了超時機制。

三階段過程

3階段提交的具體過程如下:

分散式事務,強一致性方案有哪些?|分散式事務系列(二)

第一階段:準備階段(CanCommit)

事務協調者向所有參與者傳送準備請求,並詢問參與者是否可以提交事務,並開始等待各參與者響應。參與者接收到請求後,會查詢本地資源是否可以提交,並返回查詢結果,而不需要對資源進行實際的修改操作。如果查詢資源可以提交,則回覆事務管理器“可以提交(Yes)”,否則回覆“不可以提交(No)”。

和2PC的第一階段不同的是,這裡只執行檢查,並不鎖定資源。

第二階段:預提交階段(PreCommit)

協調者根據第一階段參與者返回的結果,會出現兩種情況:執行事務預提交和中斷事務。

情況一,執行事務預提交:

  • 所有參與者返回的都是Yes響應,協調者向參與者傳送PreCommit預提交請求。
  • 參與者收到預提交請求後執行事務操作,並且記錄UndoLog和RedoLog。
  • 各個參與者返回預提交的結果給協調者,成功返回Commit提交,失敗返回Abort中止。

情況二,中斷事務:

  • 如果有任何一個參與者再階段一返回了NO,或者介面相應超時,那麼事務將中斷。
  • 協調者向各個參與者傳送中斷請求資訊。
  • 如果各個參與者收到請求,事務中斷。如果沒有收到請求,則按照超時處理,事務依舊中斷。

第三階段:確認階段(DoCommit)

根據第二階段的結果,也可以分為兩種情況,提交事務和中斷事務。

情況一,提交事務:

  • 再PreCommit階段,所有參與者返回Commit提交資訊,協調者將會從預提交轉換為提交狀態,並向所有參與者傳送doCommit請求。
  • 參與者接收到doCommit請求後,會正式執行事務操作,最終提交事務釋放資源佔用。
  • 參與者完成事務提交後向協調者傳送ack響應,協調者收到所有參與者反饋的ack後,完成事務。
  • 這一階段有可能出現沒有收到DoCommit請求,參與者會自動提交。

情況二,中斷事務

  • 在前一個階段,如果有參與者返回Abort或者相應超時,那麼事務中斷,協調者向所有參與者傳送Abort中斷請求。
  • 參與者收到請求Abort後,依賴 Undo Log 執行事務回滾,釋放鎖定的資源,並且向協調者返回Ack,反饋回滾結果。
  • 協調者收到所有參與者的回滾Ack後,中斷事務。
  • 這個階段有可能部分參與者返回回滾結果超時,或者沒有收到回滾請求(發生不一致)。

解決了2PC哪些問題

3PC解決了2PC存在的以下問題:

  1. 單點故障:3PC引入了一個準備階段,這樣即使協調者在第一階段失敗,參與者也可以在第二階段中完成提交或回滾,並且如果協調者故障參與者會自動提交,不需要一直等待。
  2. 效能問題:在3PC中,可以預先檢查參與者狀態,減少鎖定資源的情況,提高系統的效能。
  3. 阻塞問題:3PC中透過在第一階段中引入超時機制,避免了協調者一直等待的問題。如果協調者在一定時間內沒有收到所有參與者的響應,就會繼續進行第三階段的操作,從而避免了事務的阻塞問題。
  4. 部分解決資料不一致問題:在3PC中,如果在第二階段中協調者發生故障,參與者會繼續等待協調者的恢復。如果協調者無法恢復,參與者會在一定時間內自行決定提交或回滾。這樣可以部分避免2PC中的資料不一致問題。

只能說3PC對2PC存在的一些問題有改善,但沒有徹底解決。

比如它依舊存在一致性風險問題,並且風險反而略有增加。進入 PreCommit 階段之後,協調者發出的指令不是 Ack 而是 Abort,而此時因網路問題,有部分參與者直至超時都未能收到協調者的 Abort 指令的話,這些參與者將會錯誤地提交事務,這就產生了不同參與者之間資料不一致的問題。

由於3PC非常難實現,目前市面上主流的分散式事務解決方案都是2PC協議。所以,在實際應用中需要根據具體的場景和需求,選擇適合的分散式事務協議。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2942100/,如需轉載,請註明出處,否則將追究法律責任。

相關文章