可靠消息與分佈式事務


概述

前面的文章講述了Seata對分佈式事務的支持,當生產環境中沒有seata的部署時,我們如何通過可靠消息例如RocketMQ處理分佈式事務。

分佈式事務的困難

分佈式事務,全局事務就是一個分佈式系統,我們都知道,事務具有ACID特性,但是對於分佈式環境,ACID是不能完整的得到保障的。

在分佈式系統中,有個著名的CAP定理,指的是在一個分佈式系統中,一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance)。CAP 原則指的是,這三個要素最多隻能同時實現兩點,不可能三者兼顧。

但是在實際的分佈式環境中,P是一定會存在的,所以在分佈式環境中。當P出現時,我們需要在C和A之間做取捨,要和選擇CP,要麼選擇AP。

有沒有CA系統呢?有,傳統的關係型數據庫就是CA系統,因為它不會出現分區的情況,單庫提供的ACID保障,它不是分佈式的。常用的存儲系統在CAP中的取捨如下圖所示:

可靠消息與分佈式事務

由此可知,分佈式事務同樣也要在C和A之間做取捨,因此分佈式事務難做,在發生P時,我們需要放棄C和A中的一個。

事務消息的分佈式事務

在使用可靠消息做分佈式事務時,我們需要保證本地事務與消息的發送能有原子性,即本地事務成功則消息發送成功,本地事務失敗則消息不發送或消息回滾,而RocketMQ的事務消息支持兩階段提交和事務回查,能保證消息的發送與本地事務之間的原子性。

我們先看看RocketMQ官網的示例:


可靠消息與分佈式事務


TransactionListener的實現如下:


可靠消息與分佈式事務


TransactionListener的定義如下:

可靠消息與分佈式事務

其中包含兩個方法:

· executeLocalTransaction方法會在發送消息後調用,用於執行本地事務,如果本地事務執行成功,rocketmq再提交消息

· checkLocalTransaction用於對本地事務做檢查,rocketmq依賴此方法做補償,補償由rocketmq的broker主動發起,因為消息的commit或者rollback可能會失敗,因此需要這種補償機制保證消息的commit或者rollback執行成功

而當一個事務消息commit成功後,消費者才能消費到此消息,RocketMQ通過事務消息的方式提供了分佈式事務的支持。

RocketMQ事務消息的分佈式事務方案示意圖如下:

可靠消息與分佈式事務

Producer的本地事務和消息的發送是具有原子性的,因此當本地事務成功後,consumer一定會接收到消息。

但是通過RocketMQ的事務消息實現的分佈式事務是有侷限性的,它默認了當本地事務執行成功時,consumer收到消息後的業務處理一定能執行成功,一旦consumer無法完成事務,全局事務將無法回滾。舉個例子,對於庫存扣減類需求,下單後需要扣減庫存,而扣減庫存在獨立的服務中,此時如果單純的使用事務消息無法滿足,因為庫存為0後,扣減會失敗,而此時全局事務無法回滾。

對於事務消息實現的分佈式事務,它在ACID特性上的保障非常弱:

· 原子性:部分場景下能保證,但是對於庫存扣減類需求,不適合單純的使用事務消息處理分佈式事務

· 一致性:不能保證,只能得到最終一致

· 隔離性:無保證,多個事務之間不隔離

· 持久性:能保證

可靠消息實現的分佈式事務,實際上是在發生P時,選擇了A放棄了C,它是BASE原理的應用,BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)的簡寫。BASE是對CAP中一致性和可用性權衡的結果,核心思想是即使無法做到強一致性,但每個應用都可以根據自身的業務特點,採用適當的方式來使得系統達到最終一致性。

不僅僅是事務消息,TCC和Saga模式也是BASE理論的應用,特徵了一定的C。

利用事務消息做回滾

前文講述了使用事務消息完成分佈式事務的限制,且無法回滾。而我們使用服務接口調用時,在缺少TCC/Saga等分佈式事務解決方案的情況下,無法得到事務的保證,無事務的情況下整個過程的調用方式如下:

可靠消息與分佈式事務

這個過程缺少事務的保證,當系統A需要回滾時,系統B無法完成回滾,因為接口調用也可能失敗,即使系統B提供回滾接口也無法完全保證回滾成功。

我們可以通過事務消息來做回滾,這樣做雖然有些彆扭,但相比前文描述的用事務消息做分佈式事務而言,一致性雖然沒有完全得到保障,但它保障了在非回滾的場景下的一致性,整個過程如下:

可靠消息與分佈式事務

為什麼說這樣做有點彆扭,就是因為這裡將事務消息用於回滾,系統A提交事務後,需要將事務消息回滾,這樣做的目的是防止系統B消費到事務消息。

如果系統A出錯,需要回滾時,整個過程如下:

可靠消息與分佈式事務

當系統A出現異常回滾後,需要提交事務消息使得系統B可消費到事務消息從而回滾系統B的事務。

這樣做的優點:

· 實際上類似於saga模式的分佈式事務,拿MQ當事務的協調者,能用於庫存扣減類場景,場景限制少

· 當沒有發生回滾時,能保證一致性,發生回滾時,能達到最終一致

· 無額外的依賴,在沒有seata這類分佈式事務解決方案的環境下可行

缺點:

· 使用上非常彆扭,要將事務消息的提交與回滾與本地事務反過來,本地事務成功則消息事務回滾,本地事務回滾則提交消息事務


分享到:


相關文章: