當前位置:首頁 > 公眾號精選 > 架構師社區(qū)
[導讀]一個TCC事務框架需要解決的當然是分布式事務的管理。

   來源:https://www.bytesoft.org/ 

一個TCC事務框架需要解決的當然是分布式事務的管理。關于TCC事務機制的介紹,可以參考TCC事務機制簡介。
TCC事務模型雖然說起來簡單,然而要基于TCC實現一個通用的分布式事務框架,卻比它看上去要復雜的多,不只是簡單的調用一下Confirm/Cancel業(yè)務就可以了的。

本文將以Spring容器為例,試圖分析一下,實現一個通用的TCC分布式事務框架需要注意的一些問題。

一、TCC全局事務必須基于RM本地事務來實現

TCC服務是由Try/Confirm/Cancel業(yè)務構成的,其Try/Confirm/Cancel業(yè)務在執(zhí)行時,會訪問資源管理器(Resource Manager,下文簡稱RM)來存取數據。

這些存取操作,必須要參與RM本地事務,以使其更改的數據要么都commit,要么都rollback。

假設圖中的服務B沒有基于RM本地事務(以RDBS為例,可通過設置auto-commit為true來模擬),那么一旦[B:Try]操作中途執(zhí)行失敗,TCC事務框架后續(xù)決定回滾全局事務時,該[B:Cancel]則需要判斷[B:Try]中哪些操作已經寫到DB、哪些操作還沒有寫到DB.

假設[B:Try]業(yè)務有5個寫庫操作,[B:Cancel]業(yè)務則需要逐個判斷這5個操作是否生效,并將生效的操作執(zhí)行反向操作。
不幸的是,由于[B:Cancel]業(yè)務也有n(0<=n<=5)個反向的寫庫操作,此時一旦[B:Cancel]也中途出錯,則后續(xù)的[B:Cancel]執(zhí)行任務更加繁重。

因為相比第一次[B:Cancel]操作,后續(xù)的[B:Cancel]操作還需要判斷先前的[B:Cancel]操作的n(0<=n<=5)個寫庫中哪幾個已經執(zhí)行、哪幾個還沒有執(zhí)行.

這就涉及到了冪等性問題,而對冪等性的保障,又很可能還需要涉及額外的寫庫操作,該寫庫操作又會因為沒有RM本地事務的支持而存在類似問題。。。

可想而知,如果不基于RM本地事務,TCC事務框架是無法有效的管理TCC全局事務的。

反之,基于RM本地事務的TCC事務,這種情況則會很容易處理。

[B:Try]操作中途執(zhí)行失敗,TCC事務框架將其參與RM本地事務直接rollback即可。后續(xù)TCC事務框架決定回滾全局事務時,在知道“[B:Try]操作涉及的RM本地事務已經rollback”的情況下,根本無需執(zhí)行[B:Cancel]操作。

換句話說,基于RM本地事務實現TCC事務框架時,一個TCC型服務的cancel業(yè)務要么執(zhí)行,要么不執(zhí)行,不需要考慮部分執(zhí)行的情況。

二、TCC事務框架應該接管Spring容器的TransactionManager

基于RM本地事務的TCC事務框架,可以將各Try/Confirm/Cancel業(yè)務看成一個原子服務:一個RM本地事務提交,參與該RM本地事務的所有Try/Confirm/Cancel業(yè)務操作都生效;反之,則都不生效。

掌握每個RM本地事務的狀態(tài)以及它們與Try/Confirm/Cancel業(yè)務方法之間的對應關系,以此為基礎,TCC事務框架才能有效的構建TCC全局事務。

TCC服務的Try/Confirm/Cancel業(yè)務方法在RM上的數據存取操作,其RM本地事務是由Spring容器的PlatformTransactionManager來commit/rollback的,TCC事務框架想要了解RM本地事務的狀態(tài),只能通過接管Spring的事務管理器功能。

2.1. 為什么TCC事務框架需要掌握RM本地事務的狀態(tài)?
首先,根據TCC機制的定義,TCC事務是通過執(zhí)行Cancel業(yè)務來達到回滾效果的。仔細分析一下,這里暗含一個事實:
只有生效的Try業(yè)務操作才需要執(zhí)行對應的Cancel業(yè)務操作。

換句話說,只有Try業(yè)務操作所參與的RM本地事務被commit了,后續(xù)TCC全局事務回滾時才需要執(zhí)行其對應的Cancel業(yè)務操作

否則,如果Try業(yè)務操作所參與的RM本地事務被rollback了,后續(xù)TCC全局事務回滾時就不能執(zhí)行其Cancel業(yè)務,此時若盲目執(zhí)行Cancel業(yè)務反而會導致數據不一致。

其次,Confirm/Cancel業(yè)務操作必須保證生效。Confirm/Cancel業(yè)務操作也會涉及RM數據存取操作,其參與的RM本地事務也必須被commit。

TCC事務框架需要在確切的知道所有Confirm/Cancel業(yè)務操作參與的RM本地事務都被成功commit后,才能將標記該TCC全局事務為完成。

如果TCC事務框架誤判了Confirm/Cancel業(yè)務參與RM本地事務的狀態(tài),就會造成全局事務不一致。

最后,未完成的TCC全局,TCC事務框架必須重新嘗試提交/回滾操作。重試時會再次調用各TCC服務的Confirm/Cancel業(yè)務操作。

如果某個服務的Confirm/Cancel業(yè)務之前已經生效(其參與的RM本地事務已經提交),重試時就不應該再次被調用。否則,其Confirm/Cancel業(yè)務被多次調用,就會有“服務冪等性”的問題。

2.2. 攔截TCC服務的Try/Confirm/Cancel業(yè)務方法的執(zhí)行,根據其異常信息可否知道其RM本地事務是否commit/rollback了呢?

基本上很難做到,為什么這么說?
第一,事務是可以在多個(本地/遠程)服務之間互相傳播其事務上下文的,一個業(yè)務方法(Try/Confirm/Cancel)執(zhí)行完畢并不一定會觸發(fā)當前事務的commit/rollback操作。

比如,被傳播事務上下文的業(yè)務方法,在它開始執(zhí)行時,容器并不會為其創(chuàng)建新的事務,而是它的調用方參與的事務,使得二者操作在同一個事務中;同樣,在它執(zhí)行完畢時,容器也不會提交/回滾它參與的事務的。

因此,這類業(yè)務方法上的異常情況并不能反映他們是否生效。不接管Spring的TransactionManager,就無法了解事務于何時被創(chuàng)建,也無法了解它于何時被提交/回滾。
第二、一個業(yè)務方法可能會包含多個RM本地事務的情況。

比如:A(REQUIRED)->B(REQUIRES_NEW)->C(REQUIRED),這種情況下,A服務所參與的RM本地事務被提交時,B服務和C服務參與的RM本地事務則可能會被回滾。
第三、并不是拋出了異常的業(yè)務方法,其參與的事務就回滾了。

Spring容器的聲明式事務定義了兩類異常,其事務完成方向都不一樣:系統(tǒng)異常(一般為Unchecked異常,默認事務完成方向是rollback)、應用異常(一般為Checked異常,默認事務完成方向是commit)。

二者的事務完成方向又可以通過@Transactional配置顯式的指定,如rollbackFor/noRollbackFor等。
第四、Spring容器還支持使用setRollbackOnly的方式顯式的控制事務完成方向;

最后,自行攔截業(yè)務方法的攔截器和Spring的事務處理的攔截器還會存在執(zhí)行先后、攔截范圍不同等問題。

例如,如果自行攔截器執(zhí)行在前,就會出現業(yè)務方法雖然已經執(zhí)行完畢但此時其參與的RM本地事務還沒有commit/rollback。

TCC事務框架的定位應該是一個TransactionManager,其職責是負責commit/rollback事務。

而一個事務應該commit、還是rollback,則應該是由Spring容器來決定的:

Spring決定提交事務時,會調用TransactionManager來完成commit操作;Spring決定回滾事務時,會調用TransactionManager來完成rollback操作。

接管Spring容器的TransactionManager,TCC事務框架可以明確的得到Spring的事務性指令,并管理Spring容器中各服務的RM本地事務。

否則,如果通過自行攔截的機制,則使得業(yè)務系統(tǒng)存在TCC事務處理、RM本地事務處理兩套事務處理邏輯,二者互不通信,各行其是。

這種情況下要協(xié)調TCC全局事務,基本上可以說是緣木求魚,本地事務尚且無法管理,更何談管理分布式事務?

三、TCC事務框架應該具備故障恢復機制

一個TCC事務框架,若是沒有故障恢復的保障,是不成其為分布式事務框架的。

分布式事務管理框架的職責,不是做出全局事務提交/回滾的指令,而是管理全局事務提交/回滾的過程。

它需要能夠協(xié)調多個RM資源、多個節(jié)點的分支事務,保證它們按全局事務的完成方向各自完成自己的分支事務。

這一點,是不容易做到的。因為,實際應用中,會有各種故障出現,很多都會造成事務的中斷,從而使得統(tǒng)一提交/回滾全局事務的目標不能達到,甚至出現”一部分分支事務已經提交,而另一部分分支事務則已回滾”的情況。

比較常見的故障,比如:業(yè)務系統(tǒng)服務器宕機、重啟;數據庫服務器宕機、重啟;網絡故障;斷電等。這些故障可能單獨發(fā)生,也可能會同時發(fā)生。

作為分布式事務框架,應該具備相應的故障恢復機制,無視這些故障的影響是不負責任的做法。

一個完整的分布式事務框架,應該保障即使在最嚴苛的條件下也能保證全局事務的一致性,而不是只能在最理想的環(huán)境下才能提供這種保障。退一步說,如果能有所謂“理想的環(huán)境”,那也無需使用分布式事務了。

TCC事務框架要支持故障恢復,就必須記錄相應的事務日志。事務日志是故障恢復的基礎和前提,它記錄了事務的各項數據。

TCC事務框架做故障恢復時,可以根據事務日志的數據將中斷的事務恢復至正確的狀態(tài),并在此基礎上繼續(xù)執(zhí)行先前未完成的提交/回滾操作。

四、TCC事務框架應該提供Confirm/Cancel服務的冪等性保障

一般認為,服務的冪等性,是指針對同一個服務的多次(n>1)請求和對它的單次(n=1)請求,二者具有相同的副作用。

在TCC事務模型中,Confirm/Cancel業(yè)務可能會被重復調用,其原因很多。

比如,全局事務在提交/回滾時會調用各TCC服務的Confirm/Cancel業(yè)務邏輯。執(zhí)行這些Confirm/Cancel業(yè)務時,可能會出現如網絡中斷的故障而使得全局事務不能完成。

因此,故障恢復機制后續(xù)仍然會重新提交/回滾這些未完成的全局事務,這樣就會再次調用參與該全局事務的各TCC服務的Confirm/Cancel業(yè)務邏輯。

既然Confirm/Cancel業(yè)務可能會被多次調用,就需要保障其冪等性。
那么,應該由TCC事務框架來提供冪等性保障?還是應該由業(yè)務系統(tǒng)自行來保障冪等性呢?

個人認為,應該是由TCC事務框架來提供冪等性保障。如果僅僅只是極個別服務存在這個問題的話,那么由業(yè)務系統(tǒng)來負責也是可以的;

然而,這是一類公共問題,毫無疑問,所有TCC服務的Confirm/Cancel業(yè)務存在冪等性問題。TCC服務的公共問題應該由TCC事務框架來解決;

而且,考慮一下由業(yè)務系統(tǒng)來負責冪等性需要考慮的問題,就會發(fā)現,這無疑增大了業(yè)務系統(tǒng)的復雜度。

五、TCC事務框架不能盲目的依賴Cancel業(yè)務來回滾事務

前文以及提到過,TCC事務通過Cancel業(yè)務來對Try業(yè)務進行回撤的機制暗含了一個事實:Try操作已經生效。

也就是說,只有Try操作所參與的RM本地事務已經提交的情況下,才需要執(zhí)行其Cancel操作進行回撤。沒有執(zhí)行、或者執(zhí)行了但是其RM本地事務被rollback的Try業(yè)務,是一定不能執(zhí)行其Cancel業(yè)務進行回撤的。

因此,TCC事務框架在全局事務回滾時,應該根據TCC服務的Try業(yè)務的執(zhí)行情況選擇合適的處理機制。而不能盲目的執(zhí)行Cancel業(yè)務,否則就會導致數據不一致。

一個TCC服務的Try操作是否生效,這是TCC事務框架應該知道的,因為其Try業(yè)務所參與的RM事務也是由TCC事務框架所commit/rollbac的(前提是TCC事務框架接管了Spring的事務管理器)。

所以,TCC事務回滾時,TCC事務框架可考慮如下處理策略:

  1. 如果TCC事務框架發(fā)現某個服務的Try操作的本地事務尚未提交,應該直接將其回滾,而后就不必再執(zhí)行該服務的cancel業(yè)務;

  2. 如果TCC事務框架發(fā)現某個服務的Try操作的本地事務已經回滾,則不必再執(zhí)行該服務的cancel業(yè)務;

  3. 如果TCC事務框架發(fā)現某個服務的Try操作尚未被執(zhí)行過,那么,也不必再執(zhí)行該服務的cancel業(yè)務。

總之,TCC事務框架應該保障:

  1. 已生效的Try操作應該被其Cancel操作所回撤;

  2. 尚未生效的Try操作,則不應該執(zhí)行其Cancel操作。這一點,不是冪等性所能解決的問題。如上文所述,冪等性是指服務被執(zhí)行一次和被執(zhí)行n(n>0)次所產生的影響相同。但是,未被執(zhí)行和被執(zhí)行過,二者效果肯定是不一樣的,這不屬于冪等性的范疇。

六、Cancel業(yè)務與Try業(yè)務并行,甚至先于Try操作完成

這應該算TCC事務機制特有的一個不可思議的陷阱。

一般來說,一個特定的TCC服務,其Try操作的執(zhí)行,是應該在其Confirm/Cancel操作之前的。

Try操作執(zhí)行完畢之后,Spring容器再根據Try操作的執(zhí)行情況,指示TCC事務框架提交/回滾全局事務。然后,TCC事務框架再去逐個調用各TCC服務的Confirm/Cancel操作。

然而,超時、網絡故障、服務器的重啟等故障的存在,使得這個順序會被打亂。比如:

干貨!如何設計實現一個通用的分布式事務框架?

上圖中,假設[B:Try]操作執(zhí)行過程中,網絡閃斷,[A:Try]會收到一個RPC遠程調用異常。

A不處理該異常,導致全局事務決定回滾,TCC事務框架就會去調用[B:Cancel],而此刻A、B之間網絡剛好已經恢復。如果[B:Try]操作耗時較長(網絡阻塞/數據庫操作阻塞),就會出現[B:Try]和[B:Cancel]二者并行處理的現象,甚至[B:Cancel]先完成的現象。

這種情況下,由于[B:Cancel]執(zhí)行時,[B:Try]尚未生效(其RM本地事務尚未提交),因此,[B:Cancel]是不能執(zhí)行的,至少是不能生效(執(zhí)行了其RM本地事務也要rollback)的。

然而,當[B:Cancel]處理完畢(跳過執(zhí)行、或者執(zhí)行后rollback其RM本地事務)后,[B:Try]操作完成又生效了(其RM本地事務成功提交),這就會使得[B:Cancel]雖然提供了,但卻沒有起到回撤[B:Try]的作用,導致數據的不一致。

所以,TCC框架在這種情況下,需要:

  1. 將[B:Try]的本地事務標注為rollbackOnly,阻止其后續(xù)生效;

  2. 禁止其再次將事務上下文傳遞給其他遠程分支,否則該問題將在其他分支上出現;

  3. 相應地,[B:Cancel]也不必執(zhí)行,至少不能生效。

當然,TCC事務框架也可以簡單的選擇阻塞[B:Cancel]的處理,待[B:Try]執(zhí)行完畢后,再根據它的執(zhí)行情況判斷是否需要執(zhí)行[B:Cancel]。

不過,這種處理方式因為需要等待,所以,處理效率上會有所不及。

同樣的情況也會出現在confirm業(yè)務上,只不過,發(fā)生在Confirm業(yè)務上的處理邏輯與發(fā)生在Cancel業(yè)務上的處理邏輯會不一樣。

TCC框架必須保證:

  1. Confirm業(yè)務在Try業(yè)務之后執(zhí)行,若發(fā)現并行,則只能阻塞相應的Confirm業(yè)務操作;

  2. 在進入Confirm執(zhí)行階段之后,也不可以再提交同一全局事務內的新的Try操作的RM本地事務。

七、TCC服務復用性是不是相對較差?

TCC事務機制的定義,決定了一個服務需要提供三個業(yè)務實現:Try業(yè)務、Confirm業(yè)務、Cancel業(yè)務。

可能會有人因此認為TCC服務的復用性較差。怎么說呢,要是將 Try/Confirm/Cancel業(yè)務邏輯單獨拿出來復用,其復用性當然是不好的。

Try/Confirm/Cancel 邏輯作為TCC型服務中的一部分,是不能單獨作為一個組件來復用的。Try、Confirm、Cancel業(yè)務共同才構成一個組件,如果要復用,應該是復用整個TCC服務組件,而不是單獨的Try/Confirm/Cancel業(yè)務。

八、TCC服務是否需要對外暴露三個服務接口?

不需要。TCC服務與普通的服務一樣,只需要暴露一個接口,也就是它的Try業(yè)務。

Confirm/Cancel業(yè)務邏輯,只是因為全局事務提交/回滾的需要才提供的,因此Confirm/Cancel業(yè)務只需要被TCC事務框架發(fā)現即可,不需要被調用它的其他業(yè)務服務所感知。

換句話說,業(yè)務系統(tǒng)的其他服務在需要調用TCC服務時,根本不需要知道它是否為TCC型服務。

因為,TCC服務能被其他業(yè)務服務調用的也僅僅是其Try業(yè)務,Confirm/Cancel業(yè)務是不能被其他業(yè)務服務直接調用的。

九、TCC服務A的Confirm/Cancel業(yè)務中能否調用它依賴的TCC服務B的Confirm/Cancel業(yè)務?

最好不要這樣做。

首先,沒有必要。TCC服務A依賴TCC服務B,那么[A:Try]已經將事務上下文傳播給[B:Try]了,后續(xù)由TCC事務框架來調用各自的Confirm/Cancel業(yè)務即可;

其次,Confirm/Cancel業(yè)務如果被允許調用其他服務,那么它就有可能再次發(fā)起新的TCC全局事務。如此遞歸下去,將會導致全局事務關系混亂且不可控。

TCC全局事務,應該盡量在Try操作階段傳播事務上下文。Confirm/Cancel操作階段僅需要完成各自Try業(yè)務操作的確認操作/補償操作即可,不適合再做遠程調用,更不能再對外傳播事務上下文。

綜上所述,本文傾向于認為,實現一個通用的TCC分布式事務管理框架,還是相對比較復雜的。一般業(yè)務系統(tǒng)如果需要使用TCC事務機制,并不推薦自行設計實現。
這里,給大家推薦一款開源的TCC分布式事務管理器ByteTCC

https://github.com/liuyangming/ByteTCC

ByteTCC基于Try/Confirm/Cancel機制實現,可與Spring容器無縫集成,兼容Spring的聲明式事務管理。提供對dubbo框架、Spring Cloud的開箱即用的支持,可滿足多數據源、跨應用、跨服務器等各種分布式事務場景的需求。



		

		
		
		

免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據媒體報道,騰訊和網易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數據產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數據產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數字經濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉