RocketMQ事務訊息實現分析

2021-09-08 22:58:19 字數 3319 閱讀 5410

這週rocketmq發布了4.3.0版本,new feature中最受關注的一點就是支援了事務訊息:

今天花了點時間看了下具體的實現內容,下面是簡單的總結。

通過馮嘉發布的《rocketmq 4.3正式發布,支援分布式事務》一文可以看到rocketmq採用了2pc的方案來提交事務訊息,同時增加乙個補償邏輯來處理二階段超時或者失敗的訊息。

這張圖說明了事務訊息的大致方案,分為兩個邏輯:正常事務訊息的傳送及提交、事務訊息的補償流程

事務訊息傳送及提交:

傳送訊息(half訊息)

服務端響應訊息寫入結果

根據傳送結果執行本地事務(如果寫入失敗,此時half訊息對業務不可見,本地邏輯不執行)

根據本地事務狀態執行commit或者rollback(commit操作生成訊息索引,訊息對消費者可見)

補償流程:

對沒有commit/rollback的事務訊息(pending狀態的訊息),從服務端發起一次「回查」

producer收到回查訊息,檢查回查訊息對應的本地事務的狀態

根據本地事務狀態,重新commit或者rollback

補償階段用於解決訊息commit或者rollback發生超時或者失敗的情況。

整體方案是完全相同的,只是兩者的storage不同。

一階段的訊息如何對使用者不可見

事務訊息相對普通資訊最大的特點就是一階段傳送的訊息對使用者是不可見的。

如何做到寫入了訊息但是對使用者不可見?——寫入訊息資料,但是不建立對應的訊息的索引資訊。

熟悉rocketmq的同學應該都清楚,訊息在服務端的儲存結構如上,每條訊息都會有對應的索引資訊,consumer通過索引讀取訊息。

那麼實現一階段寫入的訊息不被使用者消費(需要在commit後才能消費),只需要寫入storage queue,但是不構建index queue即可。

rocketmq中具體實現策略是:寫入的如果事務訊息,對訊息的topic和queue等屬性進行替換,同時將原來的topic和queue資訊儲存到訊息的屬性中。

上圖即rocketmq替換事務訊息屬性的**實現,替換屬性後這條訊息被寫入到transactionalmessageutil.buildhalftopic()的queue 0中。

(rocketmq將事務訊息一階段傳送的訊息稱為half訊息讓人費解,採用的2pc的方式,一階段訊息稱為prepare message或者pending message更能體現它的含義)

如果讓一階段的訊息對使用者可見

在完成一階段寫入一條對使用者不可見的訊息後,二階段如果是commit操作,則需要讓訊息對使用者可見;如果是rollback則需要撤銷一階段的訊息。

先說rollback的情況。對於rollback,本身一階段的訊息對使用者是不可見的,其實不需要真正撤銷訊息(實際上rocketmq也無法去真正的刪除一條訊息,因為是順序寫檔案的)。

但是區別於這條訊息沒有確定狀態(pending狀態,事務懸而未決),需要乙個操作來標識這條訊息的最終狀態。

rocketmq事務訊息方案中引入了op訊息的概念,用op訊息標識事務訊息是否狀態已經確定(commit或者rollback)。如果一條事務訊息沒有對應的op訊息,說明這個事務的狀態還無法確定(可能是二階段失敗了)。

引入op訊息後,事務訊息無論是commit或者rollback都會記錄乙個op操作。

commit相對於rollback只是在寫入op訊息前建立half訊息的索引。

op訊息的儲存

rocketmq將op訊息寫入到全域性乙個特定的topic中:transactionalmessageutil.buildoptopic()

這個topic是乙個內部的topic(像half訊息的topic一樣),不會被使用者消費。

op訊息的內容為對應的half訊息的儲存的offset,這樣通過op訊息能索引到half訊息進行後續的回查操作。

half訊息的索引構建

在執行二階段的commit操作時,需要構建出half訊息的索引。

一階段的half訊息由於是寫到乙個特殊的topic,所以二階段構建索引時需要讀取出half訊息,並將topic和queue替換成真正的目標的topic和queue,之後通過一次普通資訊的寫入操作來生成一條對使用者可見的訊息。

所以rocketmq事務訊息二階段其實是利用了一階段儲存的訊息的內容,在二階段時恢復出一條完整的普通資訊,然後走一遍訊息寫入流程。

如何處理二階段失敗的訊息

如果二階段失敗了,比如在commit操作時出現網路問題導致commit失敗,那麼需要通過一定的策略使這條訊息最終被commit。

rocketmq採用了一種補償機制,稱為「回查」。

broker端對未確定狀態的訊息發起回查,將訊息傳送到對應的producer端(同乙個group的producer),由producer根據訊息來檢查本地事務的狀態,進而執行commit或者rollback。

broker端通過對比half訊息和op訊息進行事務訊息的回查並且推進checkpoint(記錄那些事務訊息的狀態是確定的)。

值得注意的一點是具體實現中,在回查前,系統會執行putbackhalfmsgqueue操作,即將half訊息重新寫一遍到half訊息的queue中。這麼做其實是為了能有效的推進上面的checkpoint。

rocketmq事務訊息設計總結

以上是rocketmq事務訊息實現的示意圖:

優勢:缺陷:

RocketMQ事務訊息實現分析

這週rocketmq發布了4.3.0版本,new feature中最受關注的一點就是支援了事務訊息 今天花了點時間看了下具體的實現內容,下面是簡單的總結。通過馮嘉發布的 rocketmq 4.3正式發布,支援分布式事務 一文可以看到rocketmq採用了2pc的方案來提交事務訊息,同時增加乙個補償邏...

RocketMQ 事務訊息

一 事務訊息實現方式 應用使用事務訊息的步驟 1 應用傳送訊息,使用prepare欄位標示準備訊息 2 應用執行本地業務邏輯 3 應用傳送事務提交或回滾訊息 broker收到prepare訊息後會將topic替換為rmq sys trans half topic,queueid替換為0,然後寫入co...

RocketMQ事務訊息思路

通過訊息佇列 rocketmq 事務訊息,能達到分布式事務的最終一致。模擬a賬戶轉賬給b賬戶操作,這個分布式事務有兩個子事務 子事務a areducetransaction 代表a賬戶扣款 子事務b bincreasetransaction 代表b賬戶收款 一 向訊息佇列伺服器傳送半訊息 半訊息無法...