在當前如火如荼的互聯網浪潮下,如何應對海量數據、高並發成為大家面臨的普遍難題。廣大IT公司從以往的集中式網站架構,紛紛轉向分布式的網站架構,隨之而來的就是進行數據庫拆分和應用拆分,如何在跨數據庫、跨應用保證數據操作和業務操作的一致性、原子性,又成為需要解決的新的問題。從分布式事務的需求來源來看:
1、跨數據庫
- 數據庫拆分(水平、垂直)帶來的分布式事務->保證跨庫操作的原子性
- 基於單個JVM
2、跨應用
- 應用拆分帶來的分布式事務->保證跨應用業務操作的原子性
- 跨JVM
跨應用的業務操作原子性要求,其實是比較常見的。比如在第三方支付場景中的組合支付,用戶在電商網站購物后,要同時使用余額和紅包支付該筆訂單,而余額系統和紅包系統分別是不同的應用系統,支付系統在調用這兩個系統進行支付時,就需要保證余額扣減和紅包使用要么同時成功,要么同時失敗。
TCC事務的出現正是為了解決應用拆分帶來的跨應用業務操作原子性的問題。當然,由於常規的XA事務(2PC,2 Phase Commit, 兩階段提交)性能上不盡如人意,也有通過TCC事務來解決數據庫拆分的使用場景(如賬務拆分),這個本文后續部分再詳述。
故從整個系統架構的角度來看,分布式事務的不同方案是存在層次結構的:

TCC的機制
明眼一看就知道,TCC應該是三個英文單詞的首字母縮寫而來。沒錯,TCC分別對應Try、Confirm和Cancel三種操作,這三種操作的業務含義如下:
- Try:預留業務資源
- Confirm:確認執行業務操作
- Cancel:取消執行業務操作
稍稍對照下關系型數據庫事務的三種操作:DML、Commit和Rollback,會發現和TCC有異曲同工之妙。在一個跨應用的業務操作中,Try操作是先把多個應用中的業務資源預留和鎖定住,為后續的確認打下基礎,類似的,DML操作要鎖定數據庫記錄行,持有數據庫資源;Confirm操作是在Try操作中涉及的所有應用均成功之后進行確認,使用預留的業務資源,和Commit類似;而Cancel則是當Try操作中涉及的所有應用沒有全部成功,需要將已成功的應用進行取消(即Rollback回滾)。其中Confirm和Cancel操作是一對反向業務操作。

簡而言之,TCC是應用層的2PC(2 Phase Commit, 兩階段提交),如果你將應用看做資源管理器的話。 詳細來說,TCC每項操作需要做的事情如下:1、Try:嘗試執行業務。
- 完成所有業務檢查(一致性)
- 預留必須業務資源(准隔離性)
2、Confirm:確認執行業務。
- 真正執行業務
- 不做任何業務檢查
- 只使用Try階段預留的業務資源
3、Cancel:取消執行業務
- 釋放Try階段預留的業務資源
用一張圖來說明TCC的機制:

一個完整的TCC事務參與方包括三部分:
- 主業務服務:主業務服務為整個業務活動的發起方,如前面提到的組合支付場景,支付系統即是主業務服務。
- 從業務服務:從業務服務負責提供TCC業務操作,是整個業務活動的操作方。從業務服務必須實現Try、Confirm和Cancel三個接口,供主業務服務調用。由於Confirm和Cancel操作可能被重復調用,故要求Confirm和Cancel兩個接口必須是冪等的。前面的組合支付場景中的余額系統和紅包系統即為從業務服務。
- 業務活動管理器:業務活動管理器管理控制整個業務活動,包括記錄維護TCC全局事務的事務狀態和每個從業務服務的子事務狀態,並在業務活動提交時確認所有的TCC型操作的confirm操作,在業務活動取消時調用所有TCC型操作的cancel操作。
可見整個TCC事務對於主業務服務來說是透明的,其中業務活動管理器和從業務服務各自干了一部分工作。
TCC的優點和限制
TCC事務的優點如下:
- 解決了跨應用業務操作的原子性問題,在諸如組合支付、賬務拆分場景非常實用。
- TCC實際上把數據庫層的二階段提交上提到了應用層來實現,對於數據庫來說是一階段提交,規避了數據庫層的2PC性能低下問題。
TCC事務的缺點,主要就一個:
- TCC的Try、Confirm和Cancel操作功能需業務提供,開發成本高。
當然,對TCC事務的這個缺點是否是缺點,是一個見仁見智的事情。
一個案例理解
TCC說實話,TCC的理論有點讓人費解。故接下來將以賬務拆分為例,對TCC事務的流程做一個描述,希望對理解TCC有所幫助。 賬務拆分的業務場景如下,分別位於三個不同分庫的帳戶A、B、C,A和B一起向C轉帳共80元:

1、Try:嘗試執行業務。
- 完成所有業務檢查(一致性):檢查A、B、C的帳戶狀態是否正常,帳戶A的余額是否不少於30元,帳戶B的余額是否不少於50元。
- 預留必須業務資源(准隔離性):帳戶A的凍結金額增加30元,帳戶B的凍結金額增加50元,這樣就保證不會出現其他並發進程扣減了這兩個帳戶的余額而導致在后續的真正轉帳操作過程中,帳戶A和B的可用余額不夠的情況。
2、Confirm:確認執行業務。
- 真正執行業務:如果Try階段帳戶A、B、C狀態正常,且帳戶A、B余額夠用,則執行帳戶A給賬戶C轉賬30元、帳戶B給賬戶C轉賬50元的轉帳操作。
- 不做任何業務檢查:這時已經不需要做業務檢查,Try階段已經完成了業務檢查。
- 只使用Try階段預留的業務資源:只需要使用Try階段帳戶A和帳戶B凍結的金額即可。
3、Cancel:取消執行業務
- 釋放Try階段預留的業務資源:如果Try階段部分成功,比如帳戶A的余額夠用,且凍結相應金額成功,帳戶B的余額不夠而凍結失敗,則需要對帳戶A做Cancel操作,將帳戶A被凍結的金額解凍掉。
小結:到底要不要使用TCC到底要不要使用TCC事務,取決於以下幾點:
- 是否真正有保證跨應用業務操作的原子性需求。
- 研發上能否投入資源開發相對應的TCC接口。
- 當然還有最后一點,能否搞定一個穩定的、高可用的、擴展性強的TCC事務管理器。
一個問題,如果TCC事務在Try階段所有參與方(從業務服務)成功了,但是Confirm階段部分參與方(從業務服務)成功,如何處理?
TCC參考資料
《大規模SOA系統中的分布式事務處理》:螞蟻金服CTO程立早年的一篇關於分布式事務的PPT,里面有關於大規模SOA系統中包括TCC在內的各種分布式事務處理方案,是支付寶在分布式事務實踐的經驗精華。
《Atomic Distributed Transactions: a RESTful Design》:ATOMIKOS公司的Guy Pardon和另一位作者一同寫的一篇關於TCC事務設計方案的論文,對TCC的實現細節描述較為清楚。
TCC的開源產品
可以參考一下開源的TCC實現ByteTCC。
ByteTCC是一個基於TCC(Try/Confirm/Cancel)事務補償機制的分布式事務管理器,兼容JTA,因此可以很好的與EJB、Spring等容器(本文檔下文說明中將以Spring容器為例)進行集成,支持Spring容器的聲明式事務。
用戶指南:https://github.com/liuyangming/ByteTCC/wiki
TCC是一個理念,其由Atomikos公司的創始人提出,如果想了解其具體內容直接到其官網下載個白皮書看下就好了,任何時候都是看官方文檔才能更准確的獲知答案。不過TCC只是分布式事務中的一個選項,且並非最優選項,這里有篇文章介紹
https://github.com/QNJR-GROUP/EasyTransaction
https://github.com/prontera/spring-cloud-rest-tcc
