用 Go 輕鬆完成一個 XA 事務
XA 是什麼
XA 是由 X/Open 組織提出的分佈式事務的規範,XA 規範主要定義了 (全局) 事務管理器 (TM) 和(局部)資源管理器 (RM) 之間的接口。本地的數據庫如 mysql 在 XA 中扮演的是 RM 角色
XA 一共分爲兩階段:
第一階段(prepare):即所有的參與者 RM 準備執行事務並鎖住需要的資源。參與者 ready 時,向 TM 報告已準備就緒。第二階段 (commit/rollback):當事務管理者 (TM) 確認所有參與者 (RM) 都 ready 後,向所有參與者發送 commit 命令。
目前主流的數據庫基本都支持 XA 事務,包括 mysql、oracle、sqlserver、postgre
我們看看本地數據庫是如何支持 XA 的:
第一階段 準備
XA start '4fPqCNTYeSG' -- 開啓一個 xa 事務
UPDATE `user_account` SET `balance`=balance + 30,`update_time`='2021-06-09 11:50:42.438' WHERE user_id = '1'
XA end '4fPqCNTYeSG'
XA prepare '4fPqCNTYeSG' -- 此調用之前,連接斷開,那麼事務會自動回滾
-- 當所有的參與者完成了prepare,就進入第二階段 提交
xa commit '4fPqCNTYeSG
XA 實戰
我們來完成一個完整的 XA,我們先看一個成功的 XA 時序圖:
HTTP 接入
我們來看看如何用使用 HTTP 接入一個基於 dtm-labs/dtm 的 XA 事務
gid := dtmcli.MustGenGid(dtmutil.DefaultHTTPServer)
err := dtmcli.XaGlobalTransaction(dtmutil.DefaultHTTPServer, gid, func(xa *dtmcli.Xa) (*resty.Response, error) {
resp, err := xa.CallBranch(&busi.TransReq{Amount: 30}, busi.Busi+"/TransOutXa")
if err != nil {
return resp, err
}
return xa.CallBranch(&busi.TransReq{Amount: 30}, busi.Busi+"/TransInXa")
})
app.POST(BusiAPI+"/TransInXa", dtmutil.WrapHandler2(func(c *gin.Context) interface{} {
return dtmcli.XaLocalTransaction(c.Request.URL.Query(), BusiConf, func(db *sql.DB, xa *dtmcli.Xa) error {
return AdjustBalance(db, TransInUID, reqFrom(c).Amount, reqFrom(c).TransInResult)
})
}))
app.POST(BusiAPI+"/TransOutXa", dtmutil.WrapHandler2(func(c *gin.Context) interface{} {
return dtmcli.XaLocalTransaction(c.Request.URL.Query(), BusiConf, func(db *sql.DB, xa *dtmcli.Xa) error {
return AdjustBalance(db, TransOutUID, reqFrom(c).Amount, reqFrom(c).TransOutResult)
})
}))
詳細例子代碼參考 https://github.com/dtm-labs/dtm-examples:您可以通過以下命令運行一個完整的 xa 例子:
go run main.go http_xa
上面的代碼首先註冊了一個全局 XA 事務,然後添加了兩個子事務 TransOut、TransIn。子事務全部執行成功之後,提交給 dtm。dtm 收到提交的 xa 全局事務後,會調用所有子事務的 xa commit,完成整個 xa 事務。
失敗回滾
如果有一階段 prepare 操作失敗,那麼 dtm 會調用各子事務的 xa rollback,進行回滾,最後事務成功回滾。
我們在上述 XaFireRequest 的請求負荷中,傳遞 TransInResult=FAILURE,讓他失敗
req := &busi.TransReq{Amount: 30, TransInResult: "FAILURE"}
失敗的時序圖如下:
注意點
-
dtm 的 XA 事務接口在 v1.13.0 做了一次變更,大幅簡化了 XA 事務的使用,整體上與 TCC 的接口保持一致,更易於上手。
-
XA 事務的第二階段處理,即分支的最終提交或回滾,也會發往 API
BusiAPI+"/TransOutXa"
,在這個服務的內部,dtmcli.XaLocalTransaction
會自動做xa commit | xa rollback
, 此時請求的 body 爲 nil,因此解析 body 之類的操作,如前面的reqFrom
需要放在XaLocalTransaction
內部,否則會解析 body 出錯.
小結
XA 事務的特點是:
-
簡單易理解
-
開發較容易,回滾之類的操作,由底層數據庫自動完成
-
對資源進行了長時間的鎖定,併發度低,不適合高併發的業務
聯繫我們
項目地址:https://github.com/dtm-labs/dtm 歡迎訪問,並 star 支持我們
關注【分佈式事務】公衆號,獲得更多分佈式事務相關知識
分佈式事務 介紹分佈式事務相關理論與實踐知識。 開源項目 yedf/dtm 的相關信息發佈。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/lvxEifJlFPq1POx67Tx3Kw