1. 程式人生 > >分散式事物之TCC柔性事物

分散式事物之TCC柔性事物

分散式事務之說說TCC事務

        在當前如火如荼的網際網路浪潮下,如何應對海量資料、高併發成為大家面臨的普遍難題。廣大IT公司從以往的集中式網站架構,紛紛轉向分散式的網站架構,隨之而來的就是進行資料庫拆分和應用拆分,如何在跨資料庫、跨應用保證資料操作和業務操作的一致性、原子性,又成為需要解決的新的問題。從分散式事務的需求來源來看:

1.跨資料庫

資料庫拆分(水平、垂直)帶來的分散式事務->保證跨庫操作的原子性

基於單個JVM

2.跨應用

應用拆分帶來的分散式事務->保證跨應用業務操作的原子性

跨JVM

        跨應用的業務操作原子性要求,其實是比較常見的。比如在第三方支付場景中的組合支付,使用者在電商網站購物後,要同時使用餘額和紅包支付該筆訂單,而餘額系統和紅包系統分別是不同的應用系統,支付系統在呼叫這兩個系統進行支付時,就需要保證餘額扣減和紅包使用要麼同時成功,要麼同時失敗。
        TCC事務的出現正是為了解決應用拆分帶來的跨應用業務操作原子性的問題。當然,由於常規的XA事務(2PC,2 Phase Commit, 兩階段提交)效能上不盡如人意,也有通過TCC事務來解決資料庫拆分的使用場景(如賬務拆分),這個本文後續部分再詳述。
        故從整個系統架構的角度來看,分散式事務的不同方案是存在層次結構的:

3.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事務參與方包括三部分:

  • 主業務服務:主業務服務為整個業務活動的發起方,如前面提到的組合支付場景,支付系統即是主業務服務

  • 從業務服務:從業務服務負責提供TCC業務操作,是整個業務活動的操作方。從業務服務必須實現Try、Confirm和Cancel三個介面,供主業務服務呼叫。由於Confirm和Cancel操作可能被重複呼叫,故要求Confirm和Cancel兩個介面必須是冪等的。前面的組合支付場景中的餘額系統和紅包系統即為從業務服務。

  • 業務活動管理器:業務活動管理器管理控制整個業務活動,包括記錄維護TCC全域性事務的事務狀態和每個從業務服務的子事務狀態,並在業務活動提交時確認所有的TCC型操作的confirm操作,在業務活動取消時呼叫所有TCC型操作的cancel操作。

        可見整個TCC事務對於主業務服務來說是透明的,其中業務活動管理器和從業務服務各自幹了一部分工作。

4.TCC的優點和限制

TCC事務的優點如下:

  • 解決了跨應用業務操作的原子性問題,在諸如組合支付、賬務拆分場景非常實用。

  • TCC實際上把資料庫層的二階段提交上提到了應用層來實現,對於資料庫來說是一階段提交,規避了資料庫層的2PC效能低下問題。

        TCC事務的缺點,主要就一個:TCC的Try、Confirm和Cancel操作功能需業務提供,開發成本高。

說明:當然,對TCC事務的這個缺點是否是缺點,是一個見仁見智的事情。

5.一個案例理解

        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的實現細節描述較為清楚。