初識Open/X XA
XA是DTP的一部分接口規範。
Distributed Transaction Processing(DTP)
DTP是一種實現分佈式事務處理系統的概念模型,OSI和Open/X組織都有正式文檔來定義它:
- X/Open Guide, Distributed Transaction Processing Reference Model, X/Open Company Ltd., October 1991.
- The ISO/IEC Open Systems Interconnection (OSI) Distributed Transaction Processing (DTP) standard.
- ISO/IEC DIS 10026-1 (1991) (model)
- ISO/IEC DIS 10026-2 (1991) (service)
- ISO/IEC DIS 10026-3 (1991) (protocol)
爲了簡化理解,我們只考慮它的靜態結構。在DTP的經典結構圖(下圖)中,整套系統由三種角色構成。
-
應用程序(Application Program,AP)
這個角色要做兩件事情,
一方面是定義構成整個事務所需要的所有操作(就是圖中的2,通過TX接口定義事務邊界)
另一方面是親自訪問資源節點來執行操作(就是圖中的1)。
The AP defines ** transactions ** and accesses ** resources ** within transaction boundaries.
-
資源管理器(Resource Managers,RM)
這個角色是管理着某些共享資源的自治域,比如說一個MySQL數據庫實例。在DTP裏面,還有兩個要求,
一是RM自身必須是支持事務的,
二是RM能夠根據將全局(分佈式)事務標識定位到自己內部的對應事務。
Every RM in the DTP environment must support transactions as described in Section 2.2.1 on page 4
An RM is responsible for mapping its recoverable units of work to the global transaction
-
事務管理器(Transaction Manager,TM)
這個角色能與AP和RM直接通信,協調AP和RM來實現分佈式事務的完整性。
主要的工作是
(1)、提供AP註冊全局事務的接口
(2)、頒發全局事務標識(GTID之類 的)
(3)、存儲/管理全局事務的內容
(4)、決策並指揮RM做commit/rollback。
XA是RM和TM的交互規範和接口定義,XA 就是 X/Open DTP 定義的交易中間件與數據庫之間的接口規範(即接口函數),交易中間件用它來通知數據庫事務的開始、結束以及提交、回滾等。 XA 接口函數由數據庫廠商提供,大部分數據庫都提供了XA接口實現。
更完整的一張圖如下:
eXtended Architecture(XA)
TM和RM們之間使用的是上文提到的《ISO/TEC DIS 10026-1 (1991) (model)》所定義的二階段提交。
在XA規範的描述中,兩階段提交TM協調RM們完成已定義的全局事務的方法,AP找TM申請/註冊全局事務的動作並不是二階段提交的保障內容。
二階段提交(two-phase commit)
對於單個全局(分佈式)事務,在DTP環境中,二階段提交流程大致如下:
- 第一階段(Phase 1)
TM請求所有RM進行準備(prepare commit, or prepare),並告知它們各自需要做的局部事務(transaction branche)。
RM收到請求後,如果判斷可以完成自己的局部事務,那就持久化局部事務的工作內容,再給TM肯定答覆;要是發生了其他情況,那給TM的都是否定答覆。在發送了否定答覆並回滾了局部事務之後,RM才能丟棄持久化了的局部事務信息。
- 第二階段(Phase 2)
TM根據情況(比如說所有RM都prepare成功,或者,AP通知它要rollback等),先持久化它對這個全局事務的處理決定和所涉及的RM清單,然後通知所有涉及的RM去提交(commit)或者回滾(rollback)它們的局部事務。
RM們處理完自己的局部事務後,將返回值告訴TM之後,TM纔可以清除掉包括剛纔持久化的處理決定和RM清單在內的這個全局事務的信息。
兩階段提交的協議層面優化
-
只讀斷言
在Phase 1中,RM可以斷言“我這邊不涉及數據增刪改”來答覆TM的prepare請求,從而讓這個RM脫離當前的全局事務,從而免去了Phase 2。
這種優化發生在其他RM都完成prepare之前的話,使用了只讀斷言的RM早於AP其他動作(比如說這個RM返回那些只讀數據給AP)前,就釋放了相關數據的上下文(比如讀鎖之類的),這時候其他全局事務或者本地事務就有機會去改變這些數據,結果就是無法保障整個系統的可序列化特性——通俗點說那就會有髒讀的風險。
-
一階段提交(one-phase commit)
如果需要增刪改的數據都在同一個RM上,TM可以使用一階段提交——跳過兩階段提交中的Phase 1,直接執行Phase 2。
但這種優化的本質是跳過Phase 1,這種情況下,RM自行決定了整個局部事務的結果,並且在答覆TM前就清除掉局部事務(因爲Phase 2中RM應答完請求後,TM就沒有必要去聯繫它了),這樣TM就沒有必要去持久化使用了這種優化的全局事務,也導致在某些系統故障(比如說由於網絡通信抖動,TM沒收到RM的回覆)時,TM可能會完全不知道這類事務的執行結果。
使用X/Open XA接口描述的二階段提交
X/Open的XA接口分爲兩類:
-
一類是ax_開頭的,只有ax_reg()和ax_unreg()兩個,由TM提供給RM調用,從而支撐起RM加入/退出集羣時的動態註冊機制
-
另一類是xa_開頭的,由RM提供給TM調用,用於實現二階段提交中的各種事務提交、恢復功能
下面是使用這些接口來描述的二階段提交的一個流程示意圖:
-
在開始一個全局事務之前,涉及的RM必須通過ax_regr(),向TM註冊以加入集羣;對應的,在沒有事務需要處理的時候,RM可以通過ax_unreg()向TM要求註銷,離開集羣。
-
TM在對一個RM執行xa_開頭的具體操作前,必須先通過xa_open()打開這個RM(本質是建立對話)——這其實也是分配XID的一個行爲;與之相應的,TM執行xa_close()來關閉RM。
-
TM對RM調用的xa_start()和xa_stop()這對組合,一般用於標記局部事務的開頭和結尾。這裏需要注意的有三點:
-
對於同一個RM,根據全局事務的要求,可以前後執行多對組合——俾如說,先標記一個流水賬INSERT的局部事務操作,然後再標記賬戶UPDATE的局部事務操作。
-
TM執行該組合只是起到標記事務的作用,具體的業務命令是由AP交給RM的。
-
該組合除了執行這些標記工作外,其實還能在RM中實現多線程的join/suspend/resume管理。
-
TM調用RM的xa_prepare()來進行第一階段,調用xa_commit()或xa_rollback()執行第二階段。
XA接口清單
規範中使用ISO C描述了一個xa.h的頭文件,給出了XA接口的定義。
-
ax_XXX接口
-
ax_reg
向一個TM註冊一個RM -
ax_unreg
向一個TM註銷一個RM -
xa_XXX接口
-
xa_close
停止當前AP對某個RM的使用 -
xa_commit
通知RM去提交局部事務(第二階段) -
xa_complete
詢問指定的異步xa_操作是否完成 -
xa_end
解除線程與局部事務的關聯 -
xa_forget
RM存在一種優化方式,就是在第一階段進行先行完成(heuristiccally complete)局部事務,從而儘早釋放資源(如釋放鎖等),但保留局部事務回滾能力與全局事務的對應關係等事務元數據;如果全局事務成功的話,TM通過這個接口許可RM廢棄這個事務的事務元數據 -
xa_open
初始化某個RM給當前AP使用 -
xa_prepare
通知目標RM進行第一階段工作 -
xa_recover
獲取指定RM上已完成了第一階段或者先行完成的XID清單 -
xa_rollback
通知指定RM回滾指定的局部事務 -
xa_start
啓動或恢復RM上的局部事務,換句話說,TM告訴這個RM,它後面的工作都與它現在給的XID相關。
參考
Distributed Transaction Processing: The XA Specification