­

用過XA分散式事務嗎?

  • 2019 年 11 月 20 日
  • 筆記

一、DTP模型

下圖說明了一個DTP系統的本地實例,其中AP調用TM來構造事務。這些框表示X/Open DTP模型中的軟體組件。箭頭指示控制流的方向。

圖中(3)標識的介面就是XA介面,即TM和RMs相互作用的介面(雙向介面)。XA介面不是一個普通的應用程式編程介面(API)。它是DTP軟體組件之間的系統級介面。X/Open正在開發其他DTP介面,供應用程式直接使用。

XA是由X/Open組織提出的分散式事務的規範。X/Open是一個獨立的、全球性的開放系統組織,由世界上最大的資訊系統供應商、用戶組織和軟體公司提供支援。它的使命是通過開放系統的實際實現,從計算中為用戶帶來更大的價值。

X/Open DTP(Distributed Transaction Process)是一個分散式事務模型。這個模型主要使用了兩段提交(2PC – Two-Phase-Commit)來保證分散式事務的完整性。在這個模型裡面,有三個角色

AP(An application Program),應用程式。也就是業務層,定義事務邊界並指定構成事務的操作。直白一點,哪些操作屬於一個事務,就是AP定義的。

RM(Resource Manager),資源管理器。一般是資料庫,也可以是其他的資源管理器,如消息隊列(如JMS數據源),文件系統等。提供對共享資源的訪問。

TM(Transaction Manager),事務管理器。接收AP的事務請求,對全局事務進行管理,管理事務分支狀態,協調RM的處理,通知RM哪些操作屬於哪些全局事務以及事務分支等等。這個也是整個事務調度模型的核心部分。

文章開頭的圖只是一個最簡單的模型,用於說明原理。實際系統往往會由多個簡單的模型組合起來形成一個TM域。下圖的域包括2個簡單模型。

圖中紅框的角色

CRM(Communication Resource Manager),CRM允許模型的一個實例訪問當前TM域內部或外部的另一個實例。

二、兩階段提交

所有關於分散式事務的介紹中都必然會講到兩階段提交,它是實現XA分散式事務的關鍵(確切地說:兩階段提交主要保證了分散式事務的原子性,即所有結點要麼全做要麼全不做)。兩個階段是指準備階段和提交階段。

一個描述兩階段提交很好的類比是典型的結婚儀式,每個參與者(結婚典禮中的新郎和新娘)都必須服從安排,在正式步入婚姻生活之前說「我願意」。存在一種悲劇情形,「參與者」之一在做出承諾前的最後一刻反悔。兩階段提交也類似,如果有一個參與者不確認成功,整個事務就失敗了。

當客戶端向事務管理器(TM)發出commit()請求,事務管理器開始兩階段提交過程。在第一階段,所有的資源被輪詢到,問它們是否準備好了提交作業。每個參與者可能回答「準備好(READY)」,「只讀(READ_ONLY)」,或「未準備好(NOT_READY)」。如果有任意一個參與者在第一階段響應「未準備好(NOT_READY)」,則整個事務回滾。如果所有參與者都回答「準備好(READY)」,那這些資源就在第二階段提交。回答「只讀(READ_ONLY)」的資源,則在協議的第二階段處理中被排除掉。

下圖展示了兩階段提交的基本流程

三、一般編程方式

1、配置TM,通過TM或者RM提供的方式,把RM註冊到TM。可以理解為給TM註冊RM作為數據源。一個TM可以註冊多個RM。

2、AP從TM獲取資源管理器的代理(例如:使用JTA介面,從TM管理的上下文中,獲取出這個TM所管理的RM的JDBC連接或JMS連接)

3、AP向TM發起一個全局事務。這時,TM會通知各個RM。XID(全局事務ID)會通知到各個RM。

4、AP通過2中獲取的連接,直接操作RM進行業務操作。這時,AP在每次操作時把XID(包括所屬分支的資訊)傳遞給RM,RM正是通過這個XID與3步中的XID關聯來知道操作和事務的關係的。

5、AP結束全局事務。此時TM會通知RM全局事務結束。

6、開始二段提交,也就是prepare – commit的過程。

上邊幾點更多停留在方法論的層面,我基於springboot做了個實驗

1、引入jta+atomikos依賴。jta是java對XA介面的實現,atomikos是一個事務管理器(atomikos也是最早做商用分散式事務產品的公司)

2、配置多數據源。一個是本地安裝的mysql,另一個採用公司的測試資料庫

3、編寫數據源配置程式碼

4、剩下的工作就跟springboot的寫本地事務完全一樣,用好@Transactional標籤就好。spring會幫你搞定剩下的一切功能!

很簡單就搞定了不同資料庫之間的事務問題。分散式事務是不是就是這麼簡單呢?顯然不是

四、XA的局限性

目前,Oracle、Informix、DB2和Sybase等各大資料庫廠家都提供對XA的支援,很幸運,MySQL 5.0以後的版本也支援。是不是可以放心使用MySQL的XA功能呢?我諮詢了公司的DBA。

DBA給我推薦了一篇他整理的文章

http://48fc26d1.wiz03.com/wapp/pages/view/share/s/18_2rh2TVh7v2YT4pP1INFGM1B-ldX2v2Ajd2-5SPz0niqbR

文章里提到了MySQL的XA功能存在的問題

1、阻塞問題

兩階段提交執行過程中,所有的參與者都需要聽從協調者的統一調度,期間處於阻塞狀態而不能從事其他操作,這樣效率及其低下。

2、單點故障

由於協調者的重要性,一旦協調者C發生故障。參與者si會一直阻塞下去。尤其在第二階段,協調者發生故障,那麼所有的參與者還都處於鎖定事務資源的狀態中,而無法繼續完成事務操作。(如果是協調者掛掉,可以重新選舉一個協調者,但是無法解決因為協調者宕機導致的參與者處於阻塞狀態的問題),二階段提交的缺陷在於如果C崩潰,所有Si可能都需要等待C,從而產生阻塞。

3、數據不一致

在二階段提交的階段二中,當協調者向參與者發送commit請求之後,發生了局部網路異常或者在發送commit請求過程中協調者發生了故障,這會導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是整個分散式系統便出現了數據不一致性的現象。–解決方式是

set global tx_isolation='serializable',session tx_isolation='serializable';

此外文章還詳細記錄了MySQL 外部XA崩潰恢復的過程,一些Demo程式碼以及更細節的原理分析等,推薦閱讀。

除了以上3點,現在系統都採用分散式架構,一個分散式事務很多時候不是親自去操作另一個資料庫,而是去調用其他團隊的服務。其他團隊的服務很可能不支援XA協議!

最後,支援XA協議的不只是資料庫,看看下圖的Message Broker