我們團(tuán)隊(duì)在引入go語(yǔ)言做微服務(wù)的過程中,遇見了分布式事務(wù)的強(qiáng)需求。我們的交易中心涉及大量的業(yè)務(wù),包括了商品、庫(kù)存、各類營(yíng)銷活動(dòng)、商品權(quán)限等等,按照我們微服務(wù)的設(shè)計(jì),需要拆分到多個(gè)微服務(wù)。原先由本地事務(wù)保證的ACID,現(xiàn)在需要分布式事務(wù)方案來保證交易的正確性。
我們調(diào)研了大量開源項(xiàng)目,發(fā)現(xiàn)只有java提供了分布式事務(wù)的中間件,其他語(yǔ)言,暫未發(fā)現(xiàn)成熟的方案。這種背景下,我們內(nèi)部開發(fā)了針對(duì)go語(yǔ)言分布式事務(wù)的DTM項(xiàng)目,線上穩(wěn)定之后,我們將它開源出來,github地址為:yedf/dtm 。
雖然DTM最初針對(duì)我們的go語(yǔ)言微服務(wù),但是我們的設(shè)計(jì)方案,充分考慮了跨語(yǔ)言特性,將底層通信設(shè)計(jì)成HTTP(未來會(huì)支持grpc),并且將客戶端做的非常輕,代碼量非常少。
下面我們來看一個(gè)Go語(yǔ)言接入DTM的簡(jiǎn)單例子:
const DtmServer = "http://localhost:8080/api/dtmsvr"
const startBusi = "http://localhost:8081/api/busi_saga"
req := &gin.H{"amount": 30} // 微服務(wù)的負(fù)荷
// 生成dtm的saga對(duì)象
saga := dtm.SagaNew(DtmServer).
// 添加兩個(gè)子事務(wù)
Add(startBusi+"/TransOut", startBusi+"/TransOutCompensate", req).
Add(startBusi+"/TransIn", startBusi+"/TransInCompensate", req)
// 提交saga事務(wù)
err := saga.Commit()
上述提交到dtm的saga事務(wù),包括了兩個(gè)子事務(wù),TransOut和TransIn,以及兩個(gè)子事務(wù)對(duì)應(yīng)的補(bǔ)償事務(wù)。事務(wù)提交到DTM后,DTM保證TransOut TransIn要么全部執(zhí)行成功,要么任何一個(gè)子事務(wù)失敗,會(huì)將執(zhí)行過的子事務(wù),再執(zhí)行相應(yīng)的補(bǔ)償事務(wù)。
如果TransOut、TransIn都執(zhí)行成功,時(shí)序圖如下:

如果TransOut成功、而TransIn失敗,時(shí)序圖如下:

如果您需要進(jìn)一步了解上述例子,可以移步yedf/dtm