分布式事務中Tcc模式常見問題解決

2021-10-12 07:41:47 字數 3936 閱讀 1748

在分布式系統中,隨時隨地都需要面對網路超時,網路重發和伺服器宕機等問題。所以分布式事務框架作為搭載在分布式系統之上的乙個框架型應用也繞不開這些問題。具體而言,有以下常見問題:

冪等處理

空回滾資源懸掛

這些異常的應對需要tcc框架的支援和解決方案。

因為網路抖動等原因,分布式事務框架可能會重複呼叫同乙個分布式事務中的乙個分支事務的二階段介面。所以分支事務的二階段介面confirm/cancel需要能夠保證冪等性。如果二階段介面不能保證冪等性,則會產生嚴重的問題,造成資源的重複使用或者重複釋放,進而導致業務故障。(多次執行cancel confirm   重試操作)

從上圖中紅色部分可以看到:如果當tc呼叫參與者的二階段方法時,發生了異常(tc本身異常或者網路異常丟失結果)。此時tc無法感知到呼叫的結果。為了保證分布式事務能夠走到終態,此時tc會按照一定的規則重複呼叫參與者的二階段方法。

對於冪等型別的問題,通常的手段是引入冪等字段進行防重放攻擊。對於分布式事務框架中的冪等問題,同樣可以祭出這一利器。我們可以通過增加一張事務狀態控制表來實現,這個表的關鍵字段有以下幾個:

主事務id

分支事務id

分支事務狀態

其中1和2構成表的聯合主鍵來唯一標識一筆分布式事務中的一條分支事務。3用來標識該分支事務的狀態,一共有3種狀態:

init(i) - 初始化

rollbacked® - 已回滾

冪等記錄的插入時機是參與者的try方法,此時的分支事務狀態會被初始化為init。然後當二階段的confirm/cancel執行時會將其狀態置為confirmed/rollbacked。

當tc重複呼叫二階段介面時,參與者會先獲取事務狀態控制表的對應記錄檢視其事務狀態。如果狀態已經為confirmed/rollbacked,那麼表示參與者已經處理完其分內之事,不需要再次執行,可以直接返回冪等成功的結果給tc,幫助其推進分布式事務。增加了冪等記錄的寫入和讀取判斷後,時序圖如下(藍色部分):

先來說定義,當沒有呼叫參與方try方法的情況下,就呼叫了二階段的cancel方法,cancel方法需要有辦法識別出此時try有沒有執行。如果try還沒執行,表示這個cancel操作是無效的,即本次cancel屬於空回滾;如果try已經執行,那麼執行的是正常的回滾邏輯。

如上圖所示,紅色部分的一階段try可能失敗。

首先發起方在呼叫參與者之前,會向tc申請開始一筆分布式事務。然後發起方呼叫參與者的一階段方法,在呼叫實際發生之前,一般會有切面***感知到此次try呼叫,然後寫入一條分支事務記錄。緊接著,在實際呼叫參與者的try方法時發生了異常。異常原因可以是發起方宕機,網路抖動等。

總而言之,就是try方法沒有執行成功,然而此時這筆分布式事務和分支事務已經落庫。有兩種情況會觸發分布式事務的回滾:

發起方認為當前分布式事務無法成功,主動通知tc回滾

tc發現分布式事務超時,被動觸發回滾

觸發回滾操作後,tc會對該分布式事務關聯的分支事務呼叫其二階段cancel。在執行cancel時,try還未執行成功,觸發空回滾。如果不對空回滾加以防範的話,可能會造成資源的無效釋放。即在沒有預留資源的情況下就釋放資源,造成故障。

可以發現,要應對空回滾的問題,就需要讓參與者在二階段的cancel方法中有辦法識別到一階段的try是否已經執行。

很顯然,可以繼續利用事務狀態控制表來實現這個功能。

前面提到過為了保證冪等性,當try方法被成功執行後,會插入一條記錄,標識該分支事務處於init狀態。所以後續當二階段的cancel方法被呼叫時,可以通過查詢控制表的對應記錄進行判斷。如果記錄存在且狀態為init,就表示一階段已成功執行,可以正常執行回滾操作,釋放預留的資源;如果記錄不存在則表示一階段未執行,本次為空回滾,不釋放任何資源。

時序圖如下所示:

懸掛,顧名思義,是有一些資源被懸掛起來後續無法處理了。那麼什麼場景下才會出現這種現象呢?

上一節中提到過空回滾,指的是當一階段try未執行成功,而二階段cancel就因tc回滾整個分布式事務而被呼叫。

但是考慮一種極端情況,當分布式事務到終態後,參與者的一階段try才被執行,此時參與者會根據業務需求預留相關資源。預留資源只有當前事務才能使用,然而此時分布式事務已經走到終態,後續再沒有任何手段能夠處理這些預留資源。至此,就形成了資源懸掛。

這種一階段比二階段執行的還晚的情況看似不可能,但是仔細考慮rpc呼叫的時序,其實這種情況在複雜多變的網路中是完全可能的,下面的時序展示了這種可能性:

發起方通過rpc呼叫參與者一階段try,但是發生網路阻塞導致rpc超時

rpc超時後,tc會回滾分布式事務(可能是發起方主動通知tc回滾或者是tc發現事務超時後回滾),呼叫已註冊的各個參與方的二階段cancel

參與方空回滾後,發起方對參與者的一階段try才開始執行,進行資源預留從而形成懸掛

使用時序圖來描述,紅色部分為產生資源懸掛的關鍵步驟:

資源懸掛的本質原因在於,一階段和二階段的執行順序沒有被嚴格地保證。所以相應的解決方案還是通過讀取事務狀態控制表的事務狀態。

前面在冪等方案的討論中說過:

冪等記錄的插入時機是參與者的try方法,此時的分支事務狀態會被初始化為init。然後當二階段的confirm/cancel執行時會將其狀態置為confirmed/rollbacked。

由於懸掛的產生背景是一階段方法根本就未執行,所以此時事務控制記錄是不存在的,需要在二階段中處理rollback的情況(因為超時後觸發回滾不可能存在二階段為confirm)。

處理方案為在判斷為空回滾的場景下(體現在對應一階段事務控制記錄不存在),插入一條狀態為rollbacked的控制記錄。

那麼下次當一階段try抵達執行的時候,首先會嘗試插入狀態為init的事務控制記錄。如果插入失敗,表示當前分支事務的記錄已經存在,try無需繼續執行。有幾種可能性會導致此情形:

一階段try重複請求,網路抖動情況可能發生,可以理解為命中冪等

二階段插入了防懸掛記錄,一階段不可繼續執行

時序圖描述如下,藍色部分為防止資源懸掛增加的檢查項:

前面討論了分布式事務三種典型的異常型別,它們的解決方案都依賴於一張事務狀態控制表。我們來嘗試總結一下它們各自的特點。

問題:tc重複呼叫二階段

解決:事務狀態控制記錄作為控制手段,只有存在init記錄時才執行,存在confirmed/rollbacked記錄時不再執行

問題:tc回滾事務呼叫二階段,但一階段尚未執行

解決:事務狀態控制記錄作為控制手段,無記錄時即為空回滾

問題:tc回滾事務呼叫二階段完成空回滾後,一階段執行成功

解決:事務狀態控制記錄作為控制手段,二階段發現無記錄時插入記錄,一階段執行時檢查記錄是否存在

核心的解決方案就是事務狀態控制表冪等控制作為最基礎的異常處理手段;資源懸掛的前置條件是空回滾,所以發生空回滾時會插入一條狀態為rollbacked的控制記錄

tcc分布式事務 分布式事務之TCC事務模型

我們先套乙個業務場景進去,如下圖所示 那頁面點了支付按鈕,呼叫支付服務,那我們後台要實現下面三個步驟 1 訂單服務 修改訂單狀態 2 賬戶服務 扣減金錢 3 庫存服務 扣減庫存 達到事務的效果,要麼一起成功,要麼一起失敗!就要採取tcc分布式事務方案!tcc的全稱是 try confirm canc...

TCC 分布式事務

高可用 背景 case零 tcc問題 庫存服務 並未扣減庫存數量 case一 正確情況 1 訂單服務 修改訂單狀態 成功 2 庫存服務 扣減庫存數量 成功 3 積分服務 增加會員積分 成功 4 倉儲服務 建立出庫單據 成功 case二 錯誤回滾 1 訂單服務 修改訂單狀態 成功 2 庫存服務 扣減庫...

分布式事務 TCC程式設計式模式

嚴格遵守acid的分布式事務我們稱為剛性事務,而遵循base理論 基本可用 在故障出現時保證核心功能可用,軟狀態 允許中間狀態出現,最終一致性 不要求分布式事務打成中時間點資料都是一致性的,但是保證達到某個時間點後,資料就處於了一致性了 的事務我們稱為柔性事務,其中tcc程式設計模式就屬於柔性事務,...