TCC事務介紹
TCC(Try-Confirm-Cancel)
是除可靠消息隊列以外的另一種常見的分布式事務機制,它是由數據庫專家帕特 · 赫蘭德(Pat Helland
)在2007年撰寫的論文《Life beyond Distributed Transactions: An Apostate’s Opinion》中提出的。正式以Try-Confirm-Cancel
作為名稱的是Atomikos公司,其注冊了TCC商標。
Atomikos公司在商業版本事務管理器ExtremeTransactions中提供了TCC方案的實現,但是由于其是收費的,因此相應的很多的開源實現方案也就涌現出來,如:tcc-transaction
、ByteTCC
、hmily
、spring-cloud-rest-tcc
。
上次我們分享的使用RocketMQ實現分布式事務,雖然它也能保證最終的結果是相對可靠的,過程也足夠簡單(相對于TCC來說),但可靠消息隊列的整個實現過程完全沒有任何隔離性可言。
如果業務需要隔離,我們通常就應該重點考慮TCC方案,它天生適合用于需要強隔離性的分布式事務中。
在具體實現上,TCC的操作有點復雜,它是一種業務侵入性較強的事務方案,要求業務處理過程必須拆分為“預留業務資源”和“確認/釋放消費資源”兩個子過程。另外,你看名字也能看出來,TCC的實現過程分為了三個階段:
??Try:?嘗試執行階段,完成所有業務可執行性的檢查(保障一致性),并且預留好事務需要用到的所有業務資源(保障隔離性)。
-
Confirm:?確認執行階段,不進行任何業務檢查,直接使用Try階段準備的資源來完成業務處理。注意,
Confirm
階段可能會重復執行,因此需要滿足冪等性。 -
Cancel:?取消執行階段,釋放Try階段預留的業務資源。注意,
Cancel
階段也可能會重復執行,因此也需要滿足冪等性。
空回滾和業務懸掛問題
空回滾:當某分支事務的try階段阻塞時,可能導致全局事務超時而觸發二階段的cancel操作。在未執行try操作時先執行了cancel操作,這時cancel不能做回滾,就是空回滾。
業務懸掛:對于已經空回滾的業務,如果以后繼續執行try,就永遠不可能confirm或cancel,這就是業務懸掛。應當阻止執行空回滾后的try操作,避免懸掛。
TCC與XA區別
之前分布式事務-兩階段、三階段提交介紹了二階段提交,TCC與XA兩階段提交有著異曲同工之妙。下面我們看下兩者的區別:
-
執行階段上:
-
階段1:?在XA中,各個RM準備提交各自的事務分支,事實上就是準備提交資源的更新操作(insert、delete、update等);而在TCC中,是主業務活動請求(try)各個從業務服務預留資源。
-
階段2:?XA根據第一階段每個RM是否都prepare成功,判斷是要提交還是回滾。如果都prepare成功,那么就commit每個事務分支,反之則rollback每個事務分支。TCC中,如果在第一階段所有業務資源都預留成功,那么confirm各個從業務服務,否則取消(cancel)所有從業務服務的資源預留請求。
-
-
XA是資源層面的分布式事務,強一致性,在兩階段提交的整個過程中,一直會持有資源的鎖?XA事務中的兩階段提交內部過程是對開發者屏蔽的,JTA規范中,通過
UserTransaction
的commit
方法來提交全局事務,這只是一次方法調用,其內部會委派給TransactionManager
進行真正的兩階段提交,因此開發者從代碼層面是感知不到這個過程的。而事務管理器在兩階段提交過程中,從prepare
到commit/rollback
過程中,資源實際上一直都是被加鎖的。如果有其他人需要更新這兩條記錄,那么就必須等待鎖釋放。 -
TCC是業務層面的分布式事務,最終一致性,不會一直持有資源的鎖?TCC中的兩階段提交并沒有對開發者完全屏蔽,也就是說從代碼層面,開發者是可以感受到兩階段提交的存在。如下單案例中:在第一階段,庫存中心需要提供try接口(庫存預留)。在第二階段,庫存需要提供
confirm/cancel
接口(確認庫存扣減/取消庫存預扣減)。開發者明顯的感知到了兩階段提交過程的存在。try、confirm/cancel
在執行過程中,一般都會開啟各自的本地事務,來保證方法內部業務邏輯的ACID特性。其中:-
1.?
try
過程的本地事務,是保證資源預留的業務邏輯的正確性。 -
2.?
confirm/cancel
執行的本地事務邏輯確認/取消預留資源,以保證最終一致性,也就是所謂的補償型事務(Compensation-Based Transactions
)。
-
示例
用戶購買商品的業務邏輯。整個業務邏輯由3個微服務提供支持:資金服務、紅包服務、訂單服務。
紅包服務
public?interface?RedPacketTradeOrderService?{@EnableTccpublic?String?record(RedPacketTradeOrderDto?tradeOrderDto);
}
資金服務
public?interface?CapitalTradeOrderService?{@EnableTccpublic?String?record(CapitalTradeOrderDto?tradeOrderDto);
}
訂單服務
主要業務邏輯如下:
@Service
public?class?PaymentServiceImpl?{@AutowiredCapitalTradeOrderService?capitalTradeOrderService;@AutowiredRedPacketTradeOrderService?redPacketTradeOrderService;@AutowiredOrderRepository?orderRepository;@Compensable(confirmMethod?=?"confirmMakePayment",?cancelMethod?=?"cancelMakePayment",?asyncConfirm?=?false)public?void?makePayment(@UniqueIdentity?String?orderNo)?{System.out.println("order?try?make?payment?called.time?seq:"?+?DateFormatUtils.format(Calendar.getInstance(),?"yyyy-MM-dd?HH:mm:ss"));Order?order?=?orderRepository.findByMerchantOrderNo(orderNo);String?result?=?capitalTradeOrderService.record(buildCapitalTradeOrderDto(order));String?result2?=?redPacketTradeOrderService.record(buildRedPacketTradeOrderDto(order));}public?void?confirmMakePayment(String?orderNo)?{System.out.println("order?confirm?make?payment?called.?time?seq:"?+?DateFormatUtils.format(Calendar.getInstance(),?"yyyy-MM-dd?HH:mm:ss"));Order?foundOrder?=?orderRepository.findByMerchantOrderNo(orderNo);//check?if?the?trade?order?status?is?PAYING,?if?no,?means?another?call?confirmMakePayment?happened,?return?directly,?ensure?idempotency.if?(foundOrder?!=?null)?{foundOrder.confirm();orderRepository.update(foundOrder);}}public?void?cancelMakePayment(String?orderNo)?{System.out.println("order?cancel?make?payment?called.time?seq:"?+?DateFormatUtils.format(Calendar.getInstance(),?"yyyy-MM-dd?HH:mm:ss"));Order?foundOrder?=?orderRepository.findByMerchantOrderNo(orderNo);//check?if?the?trade?order?status?is?PAYING,?if?no,?means?another?call?cancelMakePayment?happened,?return?directly,?ensure?idempotency.if?(foundOrder?!=?null)?{foundOrder.cancelPayment();orderRepository.update(foundOrder);}}
}
相關資料
開源TCC實現方案
-
https://github.com/changmingxie/tcc-transaction
-
https://github.com/liuyangming/ByteTCC
-
https://github.com/dromara/hmily
-
https://github.com/prontera/spring-cloud-rest-tcc
Atomikos的官方TCC參考文檔
-
https://www.atomikos.com/downloads/articles/TransactionsForSOA-WhitePaper.pdf
-
https://www.atomikos.com/Main/DownloadPublications?article=TccForRestApi.pdf
-
Atomikos ExtremeTransactions Guide:atomikos 商業版本事務管理器ExtremeTransactions使用指南。