我們團(tuán)隊(duì)在引入go語(yǔ)言做微服務(wù)的過(guò)程中,遇見(jiàn)了分布式事務(wù)的強(qiáng)需求敞贡。我們的交易中心涉及大量的業(yè)務(wù)泵琳,包括了商品摄职、庫(kù)存誊役、各類營(yíng)銷活動(dòng)、商品權(quán)限等等谷市,按照我們微服務(wù)的設(shè)計(jì)蛔垢,需要拆分到多個(gè)微服務(wù)。原先由本地事務(wù)保證的ACID迫悠,現(xiàn)在需要分布式事務(wù)方案來(lái)保證交易的正確性鹏漆。
我們調(diào)研了大量開(kāi)源項(xiàng)目,發(fā)現(xiàn)只有java提供了分布式事務(wù)的中間件艺玲,其他語(yǔ)言,暫未發(fā)現(xiàn)成熟的方案饭聚。這種背景下,我們內(nèi)部開(kāi)發(fā)了針對(duì)go語(yǔ)言分布式事務(wù)的DTM項(xiàng)目秒梳,線上穩(wěn)定之后法绵,我們將它開(kāi)源出來(lái),github地址為:yedf/dtm 酪碘。
雖然DTM最初針對(duì)我們的go語(yǔ)言微服務(wù)朋譬,但是我們的設(shè)計(jì)方案兴垦,充分考慮了跨語(yǔ)言特性,將底層通信設(shè)計(jì)成HTTP(未來(lái)會(huì)支持grpc)滑进,并且將客戶端做的非常輕犀忱,代碼量非常少。
下面我們來(lái)看一個(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í)行過(guò)的子事務(wù)咆蒿,再執(zhí)行相應(yīng)的補(bǔ)償事務(wù)。
如果TransOut沃测、TransIn都執(zhí)行成功,時(shí)序圖如下:
如果TransOut成功蒂破、而TransIn失敗,時(shí)序圖如下:
如果您需要進(jìn)一步了解上述例子附迷,可以移步yedf/dtm