RocketMQ分佈式事務消息原理解析

RocketMQ分佈式事務消息原理解析


事務消息

Apache RocketMQ在4.3.0版中已經支持分佈式事務消息,這裏RocketMQ採用了2PC的思想來實現了提交事務消息,同時增加一個補償邏輯來處理二階段超時或者失敗的消息,如下圖所示。

RocketMQ事務消息流程概要

上圖說明了事務消息的大致方案,其中分爲兩個流程:正常事務消息的發送及提交、事務消息的補償流程。

1.事務消息發送及提交

(1) 發送消息(half消息)。

(2) 服務端響應消息寫入結果。

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

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

2.補償流程

(1) 對沒有Commit/Rollback的事務消息(pending狀態的消息),從服務端發起一次“回查”

(2) Producer收到回查消息,檢查回查消息對應的本地事務的狀態

(3) 根據本地事務狀態,重新Commit或者Rollback

其中,補償階段用於解決消息Commit或者Rollback發生超時或者失敗的情況。

RocketMQ事務消息設計

1.事務消息在一階段對用戶不可見

在RocketMQ事務消息的主要流程中,一階段的消息如何對用戶不可見。其中,事務消息相對普通消息最大的特點就是一階段發送的消息對用戶是不可見的。那麼,如何做到寫入消息但是對用戶不可見呢?RocketMQ事務消息的做法是:如果消息是half消息,將備份原消息的主題與消息消費隊列,然後改變主題爲RMQ_SYS_TRANS_HALF_TOPIC。由於消費組未訂閱該主題,故消費端無法消費half類型的消息,然後RocketMQ會開啓一個定時任務,從Topic爲RMQ_SYS_TRANS_HALF_TOPIC中拉取消息進行消費,根據生產者組獲取一個服務提供者發送回查事務狀態請求,根據事務狀態來決定是提交或回滾消息。

在RocketMQ中,消息在服務端的存儲結構如下,每條消息都會有對應的索引信息,Consumer通過ConsumeQueue這個二級索引來讀取消息實體內容,其流程如下:

RocketMQ的具體實現策略是:寫入的如果事務消息,對消息的Topic和Queue等屬性進行替換,同時將原來的Topic和Queue信息存儲到消息的屬性中,正因爲消息主題被替換,故消息並不會轉發到該原主題的消息消費隊列,消費者無法感知消息的存在,不會消費。其實改變消息主題是RocketMQ的常用“套路”,回想一下延時消息的實現機制。

2.Commit和Rollback操作以及Op消息的引入

在完成一階段寫入一條對用戶不可見的消息後,二階段如果是Commit操作,則需要讓消息對用戶可見;如果是Rollback則需要撤銷一階段的消息。先說Rollback的情況。對於Rollback,本身一階段的消息對用戶是不可見的,其實不需要真正撤銷消息(實際上RocketMQ也無法去真正的刪除一條消息,因爲是順序寫文件的)。但是區別於這條消息沒有確定狀態(Pending狀態,事務懸而未決),需要一個操作來標識這條消息的最終狀態。RocketMQ事務消息方案中引入了Op消息的概念,用Op消息標識事務消息已經確定的狀態(Commit或者Rollback)。如果一條事務消息沒有對應的Op消息,說明這個事務的狀態還無法確定(可能是二階段失敗了)。引入Op消息後,事務消息無論是Commit或者Rollback都會記錄一個Op操作。Commit相對於Rollback只是在寫入Op消息前創建Half消息的索引。

3.Op消息的存儲和對應關係

RocketMQ將Op消息寫入到全局一個特定的Topic中通過源碼中的方法—TransactionalMessageUtil.buildOpTopic();這個Topic是一個內部的Topic(像Half消息的Topic一樣),不會被用戶消費。Op消息的內容爲對應的Half消息的存儲的Offset,這樣通過Op消息能索引到Half消息進行後續的回查操作。

在這裏插入圖片描述

4.Half消息的索引構建

在執行二階段Commit操作時,需要構建出Half消息的索引。一階段的Half消息由於是寫到一個特殊的Topic,所以二階段構建索引時需要讀取出Half消息,並將Topic和Queue替換成真正的目標的Topic和Queue,之後通過一次普通消息的寫入操作來生成一條對用戶可見的消息。所以RocketMQ事務消息二階段其實是利用了一階段存儲的消息的內容,在二階段時恢復出一條完整的普通消息,然後走一遍消息寫入流程。

5.如何處理二階段失敗的消息?

如果在RocketMQ事務消息的二階段過程中失敗了,例如在做Commit操作時,出現網絡問題導致Commit失敗,那麼需要通過一定的策略使這條消息最終被Commit。RocketMQ採用了一種補償機制,稱爲“回查”。Broker端對未確定狀態的消息發起回查,將消息發送到對應的Producer端(同一個Group的Producer),由Producer根據消息來檢查本地事務的狀態,進而執行Commit或者Rollback。Broker端通過對比Half消息和Op消息進行事務消息的回查並且推進CheckPoint(記錄那些事務消息的狀態是確定的)。

值得注意的是,rocketmq並不會無休止的的信息事務狀態回查,默認回查15次,如果15次回查還是無法得知事務狀態,rocketmq默認回滾該消息。

RocketMQ事務消息閱讀指引

RocketMQ源碼分析之從官方示例窺探RocketMQ事務消息實現基本思想
RocketMQ源碼分析之RocketMQ事務消息實現原理上篇
RocketMQ源碼分析之RocketMQ事務消息實現原理中篇----事務消息狀態回查
RocketMQ源碼分析之事務消息實現原理下篇-消息服務器Broker提交回滾事務實現原理
RocketMQ事務消息實戰

參考:https://www.cnblogs.com/fanguangdexiaoyuer/p/11662765.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章