分布式事務之TCC事務
TCC 事務介紹
在08年的軟件開發2.0技術大會上,支付寶程立在PPT大規模SOA系統中的分布事務處理,提出TCC概念。 在網絡上搜索分布式事務相關的博客,基本都會提及這個PPT,目前很多分布式事務開源項目也都是基于TCC的思想實現。
TCC 將事務提交分為 Try - Confirm - Cancel 3個操作。
- Try:預留業務資源/數據效驗
- Confirm:確認執行業務操作
- Cancel:取消執行業務操作
TCC事務處理流程和 2PC 二階段提交類似,不過 2PC通常都是在跨庫的DB層面,而TCC本質就是一個應用層面的2PC。
TCC原理圖,圖片來自阿里公眾號文章
TCC 優缺點
TCC優點:讓應用自己定義數據庫操作的粒度,使得降低鎖沖突、提高吞吐量成為可能。
TCC不足之處:
- 對應用的侵入性強。業務邏輯的每個分支都需要實現try、confirm、cancel三個操作,應用侵入性較強,改造成本高。
- 實現難度較大。需要按照網絡狀態、系統故障等不同的失敗原因實現不同的回滾策略。為了滿足一致性的要求,confirm和cancel接口必須實現冪等。
TCC 事務應用場景
我們通過用戶下單使用余額+紅包支付來看一下TCC事務的具體應用。
假設用戶下單操作來自3個系統下單系統、資金賬戶系統、紅包賬戶系統,下單成功需要同時調用資金賬戶服務和紅包服務完成支付
假設購買商品1000元,使用賬戶紅包200元,余額800元,確認支付。
-
Try操作
tryX 下單系統創建待支付訂單
tryY 凍結賬戶紅包200元
tryZ 凍結資金賬戶800元 -
Confirm操作
confirmX 訂單更新為支付成功
confirmY 扣減賬戶紅包200元
confirmZ 扣減資金賬戶800元 -
Cancel操作
cancelX 訂單處理異常,資金紅包退回,訂單支付失敗
cancelY 凍結紅包失敗,賬戶余額退回,訂單支付失敗
cancelZ 凍結余額失敗,賬戶紅包退回,訂單支付失敗
TCC 開源項目實戰 tcc-transaction
tcc-transaction 是TCC型事務Java實現,tcc-transaction不和底層使用的rpc框架耦合,也就是使用doubbo,thrift,web service,http等都可以
首先感謝開源作者無私奉獻,順手star、fork下。
在 tcc-transaction 事例中有dubbo、http實現,在這里我們使用dubbo事例。
事例的具體功能,其實就是上面介紹的 下單使用余額+紅包支付。
tcc-transaction 事務管理器日志持久化支持多種方式
引用官方1.2指南說明:tcc-transaction框架使用transactionRepository持久化事務日志??梢赃x擇FileSystemTransactionRepository、SpringJdbcTransactionRepository、RedisTransactionRepository或ZooKeeperTransactionRepository。
我們這里演示使用SpringJdbcTransactionRepository,存儲到MySQL
1. 項目準備
假設本地環境MySQL、Zookeeper都已經準備完畢
使用IDEA,將項目克隆到本地
我們使用的實例為tcc-transaction-dubbo-sample
- tcc-transaction-dubbo-capital 資金賬戶dubbo服務
- tcc-transaction-dubbo-capital-api 資金賬戶dubbo接口定義
- tcc-transaction-dubbo-order 下單系統
- tcc-transaction-dubbo-redpacket 紅包賬戶dubbo服務
- tcc-transaction-dubbo-redpacket-api 紅包賬戶dubbo接口定義
執行數據庫腳本: tcc-transaction\tcc-transaction-tutorial-sample\src\dbscripts\create_db_cap.sql (資金賬戶)
tcc-transaction\tcc-transaction-tutorial-sample\src\dbscripts\create_db_ord.sql (訂單庫)
tcc-transaction\tcc-transaction-tutorial-sample\src\dbscripts\create_db_red.sql (紅包賬戶)
tcc-transaction\tcc-transaction-tutorial-sample\src\dbscripts\create_db_tcc.sql (事務日志持久化)
修改項目配置: Zookeeper 配置
zookeeper.address=127.0.0.1:2181
如果非默認配置,需要將tcc-transaction-dubbo-sample 下的模塊全部修改
JDBC連接配置:
jdbc.driverClassName=com.mysql.jdbc.Driver
tcc.jdbc.url=jdbc:mysql://127.0.0.1:3306/TCC?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
jdbc.username=root
jdbc.password=
如果非默認配置,需要將tcc-transaction-dubbo-sample,tcc-transaction-sample-domain 下項目模塊修改
2. 項目發布
實例目前都是使用的Tomcat發布,我們先部署Tomcat:
- tcc-transaction-dubbo-capital 服務 http://192.168.10.199:8881/
- tcc-transaction-dubbo-order 服務 http://192.168.10.199:8882/
- tcc-transaction-dubbo-capital 服務 http://192.168.10.199:8883/
服務全部啟動成功:
3. 多種事務場景測試
- 第一種情況:紅包賬戶凍結成功(try)、資金賬戶凍結成功(try),訂單操作異常(try)
模擬異常代碼:
購買結果:
此時訂單支付失敗,紅包賬戶凍結金額、資金賬戶凍結金額全部退回。
通過多種類似方式測試,例如:紅包賬戶凍結異常、資金賬戶凍結異常,都會調cancel,退回凍結資源。所以在try階段的任意一方異常,都會執行全局回滾。
- 第二種情況:訂單處理成功(confirm),資金賬戶扣減成功(confirm),但紅包賬戶扣減失敗(confirm)
模擬異常代碼,在紅包扣減 confirm 操作制造異常:
購買結果:
此時訂單為支付成功,但實際紅包金額還處在凍結狀態,事務管理器記錄訂單confirm操作未執行成功,系統會不斷重試調用訂單的confirm操作,直到紅包扣減成功。
手動將紅包服務異常代碼去掉,重啟服務,等到下一次重試,紅包凍結金額被扣除成功。
- 第三種情況: 資金賬戶凍結成功(try),紅包賬戶凍結成功(try),訂單處理失敗(confirm)
模擬異常代碼,在訂單 confirm 操作制造異常:
購買結果:
此時訂單支付成功,但實際資金賬戶凍結金額、紅包凍結金額都還沒有扣除成功,事務管理器記錄訂單confirm操作未執行成功,系統會通過不斷重試訂單的confirm操作,直到資金賬戶和紅包賬戶扣減成功。
手動將異常代碼去掉,重啟服務,等到下一次重試,紅包和資金賬戶凍結金額被扣除。
- 第四種情況:在第一種情況下,訂單cancel操作處理失敗(cancel)
模擬異常代碼,在第一種情況下基礎,在cancel操作上在制造異常:
購買結果:
此時訂單支付失敗,資金賬戶、紅包賬戶凍結成功,事務管理器記錄訂單cancel操作失敗,系統會不斷重試訂單的cancel操作,直到資金賬戶和紅包賬戶凍結金額退回賬戶。
手動將異常代碼去掉,重啟服務,下一次重試cancel操作,資金賬戶和紅包賬戶凍結金額退回。
總結: try 操作成功,進入 confirm 操作,只要 confirm 處理失?。ú还苁菂f調者掛了,還是參與者處理失敗或超時),系統通過不斷重試直到處理成功。 進入 cancel 操作也是一樣,只要 cancel 處理失敗,系統通過不斷重試直到處理成功。
問題
- 對于轉賬的cancel事務,相對簡單,只要把賬務沖負即可??梢话愕臉I務邏輯會涉及很多流程、單證等操作,尤其是歷史系統,應該很難改造成tcc結構的吧,不知道你們用tcc用在什么場景下?
- 我第一次是在支付寶架構師程立PPT中聽說tcc結構的,不知道你的實現跟阿里系的實現是什么關系,目前應用的規模大嗎?
- 我理解try程序完成后,立即提交try事務,不會有鎖事務競爭??蛇@個時候賬戶余額的狀態也被設置成了類似不可讀的狀態吧,依然不可以在其他業務中查詢賬戶余額,那么這種方案比2PC優勢具體在什么地方?
回答
- 我的感覺TCC是比較適合具有較強一致性要求的場景,賬務系統就是這樣場景;應用TCC也有一定的開發成本,如果沒有強一致性要求,可以考慮其他補償型方案;
- 目前已應用在線上環境多個應用,主要就是應用賬務系統里使用;因為不是開源的,我沒有看過阿里的實現,部分借鑒了他們的思路;希望有機會能看看;
- 在Try結束后,賬戶余額會有部分資金凍結,其他業務不可以使用凍結資金;和2PC比較的話,理解下來有兩點:
- 2PC是基于資源層(如數據庫),TCC是基于SOA服務
- 2PC是是用全局事務,數據被lock的時間跨整個事務,直到全局事務結束;而TCC里每個對資源操作的是本地事務,數據被lock的時間短,可擴展性好
其實目前阿里分布式事務解決方案--GTS(Gloabel Trasaction Service)正在公測中,詳情可以參考這篇公眾號文章:GTS來了!阿里微服務架構下的分布式事務解決方案