分布式事務的幾種解決方案

2022-07-30 20:12:12 字數 3559 閱讀 9654

隨著現在分布式,微服務的普及,怎樣保證微服務之間的資料一致性就成了乙個很大的問題,也就是怎樣解決分布式事務。不像之前系統都是單點的,操作的都是同乙個資料庫,這樣系統對資料庫的操作都可以放在乙個事務中,並不需要跨系統呼叫服務。而分布式的出現,乙個大型的系統下面可能會有多個子系統模組,這時候就會出現跨系統呼叫,這時就會出現乙個問題,如果我本地系統事務執行正常,而我去呼叫系統a的時候系統a出現異常,就會導致我們兩邊的資料出現不一致的情況。下面主要講一下幾種常見的解決分布式事務的方案

xa方案也被稱為兩階段提交,基於2pc理論實現的。是有個事務管理器的概念,事務管理器負責協調多個資料庫的事務。在xa方案中分為兩階段:

第一階段:事務管理器首先向各個資料庫傳送乙個precommit預提交操作,然後由各個資料庫反饋是否可以正式提交事務

第二階段:事務管理器收到各個資料庫的反饋,如果各個資料庫都響應ok,則表明可以提交commit,如果有乙個資料庫回答不ok,那麼事務管理器就會傳送回滾事務請求

xa方案應用場景可以在sharding-jdbc中有體現,sharding-jdbc是用來分庫分表的工具,必然就會存在多個資料庫,多個資料庫源,需要保證多個資料庫中的事務要麼都成功,要麼都失敗,可以通過看個demo了解一下:

@shardingtransactiontype(transactiontype.xa)

@transactional(rollbackfor = exception.class)

public void testtransaction() catch (exception e)

}

我們從**中可以看到sharding-jdbc提供了@shardingtransactiontype註解,傳入的事務型別是xa,try{}中分別從兩個資料庫中查出了user1,user0。而更新了user1物件,user0物件。最後result=1/0丟擲異常,catch(){}中則採用transactionaspectsupport回滾操作。此時應該兩個庫中的user物件應該被回滾,網友可以去試下,寫乙個sharding-jdbc針對分布式事務的demo

xa方案在企業應用中還是用的比較少,因為xa方案還是只是在單個系統中,並沒有出現跨系統間的介面呼叫,比較適合單塊應用裡,跨多個庫的分布式事務。而且還嚴重依賴於事務管理器,一旦執行到第二個階段,事務管理器宕機了,資料庫就會一直等待commit請求,從而被阻塞住。還會出現乙個問題就是:各個資料庫之間資料不一致,加入資料庫1和資料庫2收到了commit請求,而資料庫3因為網路原因沒有收到commit請求,這時就會出現資料庫3與其他兩個庫之間的資料不一致

tcc全稱是:try、confirm、cancel

try階段:是對各個服務的資源做檢查以及對資源進行鎖定和預留,比如我要支付100元的物品,首先需要檢查你的賬戶是否夠100元進行支付,如果夠則進行鎖定

confirm階段:這個階段說的是各個服務中執行實際的操作,我支付了100元,那麼我的銀行賬戶需要扣減100元,商家賬戶就需要增加100元

cancel階段:如果任何乙個服務的業務執行操作失敗,這裡就需要將成功的進行回滾,我的賬戶扣減100元成功,商家賬戶增加100元失敗,那麼成功扣減100元也需要進行回滾

這種方案用的也比較少,主要是後面如果出現失敗,需要自己手動進行回滾,嚴重依賴於自己寫的回滾**,但是一般涉及到錢,支付的場景,tcc方案用的比較多,需要嚴格保證分布式事務要麼全部成功,要麼全部失敗,嚴格保證錢資料的一致性,還有就是各個業務之間執行的時間比較短,不然會出現資源一直被鎖定狀態

本地訊息表大概的意思就是在資料庫中建立一張訊息表,這張訊息表維護執行的事務狀態資訊,大概的步驟:

1.系統a在執行本地事務的同時,會向訊息表中插入一條資料

2.接著系統a如果需要請求系統b,這時就會傳送一條訊息到mq

3.系統b接受到了系統a傳送過來的mq訊息,首先會在自己的本地訊息表中插入一條資料,同時執行其他業務操作,如果執行成功,則會更新自己的本地訊息表的狀態和更新系統a的訊息表的狀態,表示自己處理成功

4.如果系統b執行失敗,則不會更新自己的本地訊息表和系統a的訊息表的狀態,那麼系統a會不斷的輪詢掃瞄自己的訊息表,看那些訊息狀態沒有被更新過來,訊息狀態沒有被更新過來的,會再次傳送mq訊息給系統b消費,讓系統b再次處理

本地訊息表是基於base理論實現的,保證了最終一致性,哪怕系統b執行失敗了,也會一直重發訊息,直到系統b執行成功。適用於對一致性要求不高的場景,還需要注意的一點就是重試消費mq訊息的冪等性

本地訊息表主要的問題在於嚴重依賴於資料庫的訊息表來管理兩邊的事務,如果碰上高併發場景,資料庫會成為乙個瓶頸,擴充套件性不是很高,本地訊息表用到的場景也比較少

可靠訊息最終一致性方案跟本地訊息表不同的是直接把訊息表砍掉,直接依賴於mq來實現事務,像阿里的rocketmq就支援事務,大致的意思就是:

1.首先系統a會傳送乙個prepare訊息到mq,如果prepare訊息傳送失敗,後面的操作也別執行了

2.系統a傳送prepare訊息成功,開始執行本地事務,如果本地事務執行成功則告訴mq傳送確認訊息,如果本地事務執行失敗,則告訴mq執行回滾訊息,需要將prepare訊息回撤掉

3.如果是傳送確認訊息,系統b接受到mq傳送過來的訊息,執行本地的事務,如果系統b執行本地事務失敗,自動不斷重試直到成功。如果還是一直不成功,則傳送報警由人工來手工回滾和補償,只能人工手動的修資料。

4.假設mq接受到了系統a傳送過來的prepare訊息,但是一直沒收到確認傳送還是回滾操作,那麼mq會定時的輪詢所有prepare訊息來**系統a的介面,來檢查系統a執行本地事務的時候是不是失敗了,自己在**介面中的業務可以自定義如果本地事務執行失敗,那麼傳送到mq的prepare訊息也進行回滾操作

這種方案在企業應用中還是使用的比較多的,一些大型網際網路企業都是依賴於mq來實現最終訊息的一致性,像rocketmq本身就支援事務,提供了transactionlistener介面,我們只需要實現介面中的checklocaltransaction的方法,也就是mq沒有收到確認傳送還是回滾的操作需要**的介面。雖然rabbitmq、activemq沒有現成的支援事務,但是也可以基於rocketmq的思路來封裝一套類似的邏輯出來

上面幾種方案需要真正落地的話,實現起來還是比較麻煩的,如果要實現分布式事務,需要考慮到的點還是比較多的,複雜度也比較大。能不用分布式事務的話就不用,如果非得使用的話,看能不能使用一些補償機制去實現,最後再結合自己公司的業務分析,來看看哪一種方案適合自己的業務

事務 分布式事務解決方案

事務acid特性 事務隔離級別 指的是讀和寫同時出現時出現的資料不一致問題。事務的一致性問題 存在問題問題描述 髒讀 dirty read 針對的是單條資料。即乙個更新操作a修改了某一條資料,但尚未提交該事務,此時另乙個讀操作b來查詢該條資料,讀到的是修改後的但尚未提交的資料。不可重複讀 unrep...

分布式事務解決方案

一 結合mq訊息中介軟體實現的可靠訊息最終一致性 二 tcc補償性事務解決 三 最大努力通知型方案 第一種方案 可靠訊息最終一致性,需要業務系統結合mq訊息中介軟體實現,在實現過程中需要保證訊息的成功傳送及成功消費。即需要通過業務系統控制mq的訊息狀態 第二種方案 tcc補償性,分為三個階段tryi...

分布式事務解決方案

當資料庫單錶一年產生的資料超過1000w,那麼就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以後有空詳細說,簡單的說就是原來的乙個資料庫變成了多個資料庫。這時候,如果乙個操作既訪問01庫,又訪問02庫,而且要保證資料的一致性,那麼就要用到分布式事務。所謂的soa化,就是業務的服務化。比如原來單機...