用python輕松完成一個(gè)分布式事務(wù)TCC,保姆級(jí)教程
作者:葉東富
來(lái)源:SegmentFault 思否社區(qū)
什么是分布式事務(wù)?銀行跨行轉(zhuǎn)賬業(yè)務(wù)是一個(gè)典型分布式事務(wù)場(chǎng)景,假設(shè)A需要跨行轉(zhuǎn)賬給B,那么就涉及兩個(gè)銀行的數(shù)據(jù),無(wú)法通過(guò)一個(gè)數(shù)據(jù)庫(kù)的本地事務(wù)保證轉(zhuǎn)賬的ACID,只能夠通過(guò)分布式事務(wù)來(lái)解決。
分布式事務(wù)就是指事務(wù)的發(fā)起者、資源及資源管理器和事務(wù)協(xié)調(diào)者分別位于分布式系統(tǒng)的不同節(jié)點(diǎn)之上。在上述轉(zhuǎn)賬的業(yè)務(wù)中,用戶A-100操作和用戶B+100操作不是位于同一個(gè)節(jié)點(diǎn)上。本質(zhì)上來(lái)說(shuō),分布式事務(wù)就是為了保證在分布式場(chǎng)景下,數(shù)據(jù)操作的正確執(zhí)行。
什么是TCC分布式事務(wù),TCC是Try、Confirm、Cancel三個(gè)詞語(yǔ)的縮寫(xiě),最早是由 Pat Helland 于 2007 年發(fā)表的一篇名為《Life beyond Distributed Transactions:an Apostate’s Opinion》的論文提出。
TCC組成
TCC分為3個(gè)階段
Try 階段:嘗試執(zhí)行,完成所有業(yè)務(wù)檢查(一致性), 預(yù)留必須業(yè)務(wù)資源(準(zhǔn)隔離性)
Confirm 階段:如果所有分支的Try都成功了,則走到Confirm階段。Confirm真正執(zhí)行業(yè)務(wù),不作任何業(yè)務(wù)檢查,只使用 Try 階段預(yù)留的業(yè)務(wù)資源
Cancel 階段:如果所有分支的Try有一個(gè)失敗了,則走到Cancel階段。Cancel釋放 Try 階段預(yù)留的業(yè)務(wù)資源。
AP/應(yīng)用程序,發(fā)起全局事務(wù),定義全局事務(wù)包含哪些事務(wù)分支
RM/資源管理器,負(fù)責(zé)分支事務(wù)各項(xiàng)資源的管理
TM/事務(wù)管理器,負(fù)責(zé)協(xié)調(diào)全局事務(wù)的正確執(zhí)行,包括Confirm,Cancel的執(zhí)行,并處理網(wǎng)絡(luò)異常

TCC實(shí)踐
@app.post("/api/TransOutTry")
def trans_out_try():
return {"dtm_result": "SUCCESS"}
@app.post("/api/TransOutConfirm")
def trans_out_confirm():
return {"dtm_result": "SUCCESS"}
@app.post("/api/TransOutCancel")
def trans_out_cancel():
return {"dtm_result": "SUCCESS"}
@app.post("/api/TransInTry")
def trans_in_try():
return {"dtm_result": "SUCCESS"}
@app.post("/api/TransInConfirm")
def trans_in_confirm():
return {"dtm_result": "SUCCESS"}
@app.post("/api/TransInCancel")
def trans_in_cancel():
return {"dtm_result": "SUCCESS"}
# 這是dtm服務(wù)地址
dtm = "http://localhost:8080/api/dtmsvr"
# 這是業(yè)務(wù)微服務(wù)地址
svc = "http://localhost:5000/api"
@app.get("/api/fireTcc")
def fire_tcc():
# 發(fā)起tcc事務(wù),其中tcc_trans進(jìn)行具體的業(yè)務(wù)處理
gid = tcc.tcc_global_transaction(dtm, tcc_trans)
return {"gid": gid}
# tcc事務(wù)的具體處理
def tcc_trans(t):
req = {"amount": 30} # 業(yè)務(wù)請(qǐng)求的負(fù)荷
# 調(diào)用轉(zhuǎn)出服務(wù)的Try|Confirm|Cancel
t.call_branch(req, svc + "/TransOutTry", svc + "/TransOutConfirm", svc + "/TransOutCancel")
# 調(diào)用轉(zhuǎn)入服務(wù)的Try|Confirm|Cancel
t.call_branch(req, svc + "/TransInTry", svc + "/TransInConfirm", svc + "/TransInCancel")
# 部署啟動(dòng)dtm
# 需要docker版本18以上
git clone https://github.com/yedf/dtm
cd dtm
docker-compose up
# 另起一個(gè)命令行
git clone https://github.com/yedf/dtmcli-py-sample
cd dtmcli-py-sample
pip3 install flask dtmcli requests
flask run
# 另起一個(gè)命令行
curl localhost:5000/api/fireTcc
TCC的回滾
@app.post("/api/TransInTry")
def trans_in_try():
return {"dtm_result": "FAILURE"}

這個(gè)跟成功的TCC差別就在于,當(dāng)某個(gè)子事務(wù)返回失敗后,后續(xù)就回滾全局事務(wù),調(diào)用各個(gè)子事務(wù)的Cancel操作,保證全局事務(wù)全部回滾。
TCC網(wǎng)絡(luò)異常
小結(jié)

