MQ實現(xiàn)分布式事務(wù)

在系統(tǒng)A處理任務(wù)A前,首先向消息中間件發(fā)送一條消息

消息中間件收到后將該條消息持久化,但并不投遞。此時下游系統(tǒng)B仍然不知道該條消息的存在。

消息中間件持久化成功后,便向系統(tǒng)A返回一個確認應(yīng)答;

系統(tǒng)A收到確認應(yīng)答后,則可以開始處理任務(wù)A;

任務(wù)A處理完成后,向消息中間件發(fā)送Commit請求。該請求發(fā)送完成后,對系統(tǒng)A而言,該事務(wù)的處理過程就結(jié)束了,此時它可以處理別的任務(wù)了。

但commit消息可能會在傳輸途中丟失,從而消息中間件并不會向系統(tǒng)B投遞這條消息,從而系統(tǒng)就會出現(xiàn)不一致性。這個問題由消息中間件的事務(wù)回查機制完成,下文會介紹。

消息中間件收到Commit指令后,便向系統(tǒng)B投遞該消息,從而觸發(fā)任務(wù)B的執(zhí)行;

當任務(wù)B執(zhí)行完成后,系統(tǒng)B向消息中間件返回一個確認應(yīng)答,告訴消息中間件該消息已經(jīng)成功消費,此時,這個分布式事務(wù)完成。

上面所介紹的Commit和Rollback都屬于理想情況,但在實際系統(tǒng)中,Commit和Rollback指令都有可能在傳輸途中丟失。那么當出現(xiàn)這種情況的時候,消息中間件是如何保證數(shù)據(jù)一致性呢?——答案就是超時詢問機制。

系統(tǒng)A除了實現(xiàn)正常的業(yè)務(wù)流程外,還需提供一個事務(wù)詢問的接口,供消息中間件調(diào)用。當消息中間件收到一條事務(wù)型消息后便開始計時,如果到了超時時間也沒收到系統(tǒng)A發(fā)來的Commit或Rollback指令的話,就會主動調(diào)用系統(tǒng)A提供的事務(wù)詢問接口詢問該系統(tǒng)目前的狀態(tài)。該接口會返回三種結(jié)果:

提交

若獲得的狀態(tài)是“提交”,則將該消息投遞給系統(tǒng)B。

回滾

若獲得的狀態(tài)是“回滾”,則直接將條消息丟棄。

處理中

若獲得的狀態(tài)是“處理中”,則繼續(xù)等待。

---------------------

消息中間件的超時詢問機制能夠防止上游系統(tǒng)因在傳輸過程中丟失Commit/Rollback指令而導(dǎo)致的系統(tǒng)不一致情況,而且能降低上游系統(tǒng)的阻塞時間,上游系統(tǒng)只要發(fā)出Commit/Rollback指令后便可以處理其他任務(wù),無需等待確認應(yīng)答。而Commit/Rollback指令丟失的情況通過超時詢問機制來彌補,這樣大大降低上游系統(tǒng)的阻塞時間,提升系統(tǒng)的并發(fā)度。

---------------------

下面來說一說消息投遞過程的可靠性保證。

當上游系統(tǒng)執(zhí)行完任務(wù)并向消息中間件提交了Commit指令后,便可以處理其他任務(wù)了,此時它可以認為事務(wù)已經(jīng)完成,接下來消息中間件一定會保證消息被下游系統(tǒng)成功消費掉!那么這是怎么做到的呢?這由消息中間件的投遞流程來保證。

消息中間件向下游系統(tǒng)投遞完消息后便進入阻塞等待狀態(tài),下游系統(tǒng)便立即進行任務(wù)的處理,任務(wù)處理完成后便向消息中間件返回應(yīng)答。消息中間件收到確認應(yīng)答后便認為該事務(wù)處理完畢!

如果消息在投遞過程中丟失,或消息的確認應(yīng)答在返回途中丟失,那么消息中間件在等待確認應(yīng)答超時之后就會重新投遞,直到下游消費者返回消費成功響應(yīng)為止。當然,一般消息中間件可以設(shè)置消息重試的次數(shù)和時間間隔,比如:當?shù)谝淮瓮哆f失敗后,每隔五分鐘重試一次,一共重試3次。如果重試3次之后仍然投遞失敗,那么這條消息就需要人工干預(yù)。

---------------------

有的同學可能要問:消息投遞失敗后為什么不回滾消息,而是不斷嘗試重新投遞?

這就涉及到整套分布式事務(wù)系統(tǒng)的實現(xiàn)成本問題。

我們知道,當系統(tǒng)A將向消息中間件發(fā)送Commit指令后,它便去做別的事情了。如果此時消息投遞失敗,需要回滾的話,就需要讓系統(tǒng)A事先提供回滾接口,這無疑增加了額外的開發(fā)成本,業(yè)務(wù)系統(tǒng)的復(fù)雜度也將提高。對于一個業(yè)務(wù)系統(tǒng)的設(shè)計目標是,在保證性能的前提下,最大限度地降低系統(tǒng)復(fù)雜度,從而能夠降低系統(tǒng)的運維成本。

---------------------

首先,上游系統(tǒng)和消息中間件之間采用異步通信是為了提高系統(tǒng)并發(fā)度。業(yè)務(wù)系統(tǒng)直接和用戶打交道,用戶體驗尤為重要,因此這種異步通信方式能夠極大程度地降低用戶等待時間。此外,異步通信相對于同步通信而言,沒有了長時間的阻塞等待,因此系統(tǒng)的并發(fā)性也大大增加。但異步通信可能會引起Commit/Rollback指令丟失的問題,這就由消息中間件的超時詢問機制來彌補。

那么,消息中間件和下游系統(tǒng)之間為什么要采用同步通信呢?

異步能提升系統(tǒng)性能,但隨之會增加系統(tǒng)復(fù)雜度;而同步雖然降低系統(tǒng)并發(fā)度,但實現(xiàn)成本較低。因此,在對并發(fā)度要求不是很高的情況下,或者服務(wù)器資源較為充裕的情況下,我們可以選擇同步來降低系統(tǒng)的復(fù)雜度。

我們知道,消息中間件是一個獨立于業(yè)務(wù)系統(tǒng)的第三方中間件,它不和任何業(yè)務(wù)系統(tǒng)產(chǎn)生直接的耦合,它也不和用戶產(chǎn)生直接的關(guān)聯(lián),它一般部署在獨立的服務(wù)器集群上,具有良好的可擴展性,所以不必太過于擔心它的性能,如果處理速度無法滿足我們的要求,可以增加機器來解決。而且,即使消息中間件處理速度有一定的延遲那也是可以接受的,因為前面所介紹的BASE理論就告訴我們了,我們追求的是最終一致性,而非實時一致性,因此消息中間件產(chǎn)生的時延導(dǎo)致事務(wù)短暫的不一致是可以接受的。

---------------------

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容