Spring Cloud異步場景分布式事務(wù)怎樣做波势?試試RocketMQ

mark

一翎朱、背景

在微服務(wù)架構(gòu)中,我們常常使用異步化的手段來提升系統(tǒng)的 吞吐量解耦 上下游尺铣,而構(gòu)建異步架構(gòu)最常用的手段就是使用 消息隊列(MQ)拴曲,那異步架構(gòu)怎樣才能實現(xiàn)數(shù)據(jù)一致性呢?本文主要介紹如何使用RocketMQ事務(wù)消息來解決一致性問題凛忿。

RocketMQ 是阿里巴巴開源的分布式消息中間件澈灼,目前已成為 Apache 的頂級項目。歷經(jīng)多次天貓雙十一海量消息考驗店溢,具有高性能叁熔、低延時和高可靠等特性

PS:同步場景怎樣保證一致性?請看文章《Spring Cloud同步場景分布式事務(wù)怎樣做床牧?試試Seata

?

二荣回、MQ選型

可以看到在 業(yè)務(wù)處理 方面來說 RocketMQ 優(yōu)于其他對手,而且原生支持 事務(wù)消息

mark

PS:業(yè)務(wù)系統(tǒng)用的是其他 MQ 產(chǎn)品但是又需要 事務(wù)消息 怎么辦戈咳?學習原理自己開發(fā)實現(xiàn)心软!

?

三、什么是事務(wù)消息

例如下圖的場景:生成訂單記錄 -> MQ -> 增加積分

mark

我們是應(yīng)該先 創(chuàng)建訂單記錄著蛙,還是先 發(fā)送MQ消息 呢删铃?

  1. 先發(fā)送MQ消息:這個明顯是不行的,因為如果消息發(fā)送成功册踩,而訂單創(chuàng)建失敗的話是沒辦法把消息收回來的

  2. 先創(chuàng)建訂單記錄:如果訂單創(chuàng)建成功后MQ消息發(fā)送失敗 拋出異常泳姐,因為兩個操作都在本地事務(wù)中所以訂單數(shù)據(jù)是可以 回滾

上面的 方式二 看似沒問題,但是 網(wǎng)絡(luò)是不可靠的暂吉!如果 MQ 的響應(yīng)因為網(wǎng)絡(luò)原因沒有收到胖秒,所以在面對不確定的結(jié)果只好進行回滾缎患;但是 MQ 端又確實是收到了這條消息的,只是回給客戶端的 響應(yīng)丟失 了阎肝!
?
所以 事務(wù)消息 就是用來保證 本地事務(wù)MQ消息發(fā)送 的原子性挤渔!

?

四、RocketMQ事務(wù)消息原理

mark

主要的邏輯分為兩個流程:

  • 事務(wù)消息發(fā)送及提交
    1. 發(fā)送 half消息
    2. MQ服務(wù)端 響應(yīng)消息寫入結(jié)果
    3. 根據(jù)發(fā)送結(jié)果執(zhí)行 本地事務(wù)(如果寫入失敗风题,此時half消息對業(yè)務(wù) 不可見判导,本地邏輯不執(zhí)行)
    4. 根據(jù)本地事務(wù)狀態(tài)執(zhí)行 Commit 或者 Rollback(Commit操作生成消息索引,消息對消費者 可見
      ?
  • 回查流程
    1. 對于長時間沒有 Commit/Rollback 的事務(wù)消息(pending 狀態(tài)的消息)沛硅,從服務(wù)端發(fā)起一次 回查
    2. Producer 收到回查消息眼刃,檢查回查消息對應(yīng)的 本地事務(wù)狀態(tài)
    3. 根據(jù)本地事務(wù)狀態(tài),重新 Commit 或者 Rollback

?
邏輯時序圖

mark

?

五摇肌、異步架構(gòu)一致性實現(xiàn)思路

從上面的原理可以發(fā)現(xiàn) 事務(wù)消息 僅僅只是保證本地事務(wù)和MQ消息發(fā)送形成整體的 原子性擂红,而投遞到MQ服務(wù)器后,并無法保證消費者一定能消費成功围小!
?
如果 消費端消費失敗 后的處理方式昵骤,建議是記錄異常信息然后 人工處理,并不建議回滾上游服務(wù)的數(shù)據(jù)(因為兩者是 解耦 的肯适,而且 復(fù)雜度 太高)
?
我們可以利用 MQ 的兩個特性 重試死信隊列 來協(xié)助消費端處理:

  1. 消費失敗后進行一定次數(shù)的 重試
  2. 重試后也失敗的話該消息丟進 死信隊列
  3. 另外起一個線程監(jiān)聽消費 死信隊列 里的消息变秦,記錄日志并且預(yù)警!

因為有 重試 所以消費者需要實現(xiàn) 冪等性

?

六框舔、分布式事務(wù)場景樣例

下面就用剛剛提到的場景:生成訂單記錄 -> MQ -> 增加積分蹦玫;來簡單講一下 Spring Cloud 中應(yīng)該怎么做,詳細代碼請 下載demo 查看雨饺。
PS:怎樣安裝部署RocketMQ可以參考《Apache RocketMQ 消息隊列部署與可視化界面安裝

6.1. 引入依賴

使用 spring-cloud-stream 框架來訪問 RocketMQ

mark

Spring Cloud Stream 是一個構(gòu)建消息驅(qū)動的框架钳垮,通過抽象的定義實現(xiàn)應(yīng)用與MQ消息隊列之間的解耦,目前支持 RabbitMQ额港、kafkaRocketMQ

mark

?

6.2. 開啟事務(wù)消息

消息生產(chǎn)者需要添加 transactional: true 開啟 事務(wù)消息

mark

?

6.3. 訂單服務(wù)發(fā)送half消息

mark

因為開啟了 事務(wù)消息 所以這里發(fā)送的是 half消息 對于消費端是 不可見

?

6.4. 訂單服務(wù)監(jiān)聽half消息

使用 @RocketMQTransactionListener 注解監(jiān)聽 半消息,并實現(xiàn) RocketMQLocalTransactionListener 接口歧焦,該接口有兩個方法

  • executeLocalTransaction:用于提交本地事務(wù)
  • checkLocalTransaction:用于事務(wù)回查
mark

如果提交事務(wù)消息失敗移斩,需等待約1分鐘左右 事務(wù)回查 方法才會被調(diào)用

?

6.5. 積分服務(wù)消費消息

mark

注意:因為有 重試,這里如果是真實的業(yè)務(wù)需要自行實現(xiàn) 冪等性

?

6.6. 消費死信隊列預(yù)警

mark

監(jiān)聽并消費死信隊列中的消息绢馍,用于記錄錯誤日志向瓷,并且預(yù)警通知運維人員等

?

6.7. 測試用例

demo中提供了3個接口分別測試不同的場景:

  • 事務(wù)成功
    http://localhost:11002/success
    流程如下:

    1. 訂單創(chuàng)建 成功
    2. 提交事務(wù)消息 成功
    3. 消費消息增加積分 成功
  • 訂單創(chuàng)建成功但提交事務(wù)消息失敗
    http://localhost:11002/produceError
    流程如下:

    1. 訂單創(chuàng)建 成功
    2. 提交事務(wù)消息 失敗
    3. 事務(wù)回查(等待1分鐘左右) 成功
    4. 提交事務(wù)消息 成功
    5. 消費消息增加積分 成功
  • 消費消息失敗
    http://localhost:11002/consumeError
    流程如下:

    1. 訂單創(chuàng)建 成功
    2. 提交事務(wù)消息 成功
    3. 消費消息增加積分 失敗
    4. 重試消費消息 失敗
    5. 進入死信隊列 成功
    6. 消費死信隊列的消息 成功
    7. 記錄日志并發(fā)出預(yù)警 成功

?

七、demo下載地址

https://gitee.com/zlt2000/microservices-platform/tree/master/zlt-demo/rocketmq-demo/rocketmq-transactional

?

推薦閱讀

?
掃碼關(guān)注有驚喜朱躺!

file
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刁赖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子长搀,更是在濱河造成了極大的恐慌宇弛,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件源请,死亡現(xiàn)場離奇詭異枪芒,居然都是意外死亡,警方通過查閱死者的電腦和手機谁尸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門舅踪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人良蛮,你說我怎么就攤上這事抽碌。” “怎么了背镇?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵咬展,是天一觀的道長。 經(jīng)常有香客問我瞒斩,道長破婆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任胸囱,我火速辦了婚禮祷舀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烹笔。我一直安慰自己裳扯,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布谤职。 她就那樣靜靜地躺著饰豺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪允蜈。 梳的紋絲不亂的頭發(fā)上冤吨,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音饶套,去河邊找鬼漩蟆。 笑死,一個胖子當著我的面吹牛妓蛮,可吹牛的內(nèi)容都是我干的怠李。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捺癞!你這毒婦竟也來了夷蚊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤翘簇,失蹤者是張志新(化名)和其女友劉穎撬码,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體版保,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡呜笑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了彻犁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叫胁。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汞幢,靈堂內(nèi)的尸體忽然破棺而出驼鹅,到底是詐尸還是另有隱情,我是刑警寧澤森篷,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布输钩,位于F島的核電站,受9級特大地震影響仲智,放射性物質(zhì)發(fā)生泄漏买乃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一钓辆、第九天 我趴在偏房一處隱蔽的房頂上張望剪验。 院中可真熱鬧,春花似錦前联、人聲如沸功戚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啸臀。三九已至,卻和暖如春烁落,著一層夾襖步出監(jiān)牢的瞬間壳咕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工顽馋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幌羞。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓寸谜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親属桦。 傳聞我的和親對象是個殘疾皇子熊痴,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容