日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RocketMQ的分布式事务解决方案

發布時間:2024/1/23 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RocketMQ的分布式事务解决方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

在系統變的復雜后,分布式、微服務等架構技術,就要考慮到應用在系統中了。尤其數據量大了后,就需要對數據庫進行拆分

如:注冊的用戶數據,量大了后,就需要考慮分庫分表

一旦數據庫進行了分拆,那就出現很多頭疼的問題,其中之一就是事務問題。那我們就來看看問題是怎么出現的?

場景

?

?

先來上個圖

進行數據拆分后,就類似上面的架構

上圖中我們就拿用戶的數據進行舉例,用戶量一旦幾千萬時,就需要進行分庫分表;上圖就分了3個庫,每個庫都保證了高可用。

這樣的架構設計,會遇到事務問題,我們來看看具體的業務場景:用戶A轉賬100元給用戶B,這個業務比較簡單,我們來分析一下里面具體的步驟

1、用戶A的賬戶先扣除100元 2、再把用戶B的賬戶加100元

?

?

邏輯很簡單,上偽代碼

代碼也是比較清晰的,感覺沒有什么問題,那我們來分析一下問題在哪?

問題

我們看到在轉賬業務中,有兩步,一個是操作用戶A扣錢,一個是操作用戶B加錢

如果在同一個數據庫中進行,可以保證這兩步操作,要么同時成功,要么同時不成功。這樣就保證了轉賬的數據一致性。

但是如果用戶A的數據在集群A中,用戶B在集群B中呢?因為他們不在同一個事務中;如用戶A扣款成功,但用戶B加錢失敗了;那就坑了,數據不完整了。

類似這種問題在微服務架構會更多,因為各個服務都是獨立的模塊,都是遠程調用,都沒法在同一個事務中,都會遇到事務問題。

那怎么解決?網上有一些方案,如:兩階段提交,TCC等,還有常用就是最終一致性方案。今天就給大家介紹一下如何利用消息中間件去解決。那我們就把方案調整一下,加入消息中間件,看看如何優化。

消息中間件方案

上圖就是利用消息中間件的方式,把扣款業務和加錢業務異步化,扣款成功后,發送“扣款成功消息”到消息中間件;加錢業務訂閱“扣款成功消息”,再對用戶B加錢

系統怎么知道給用戶B加錢呢?是消息體里面包含了源賬戶和目標賬戶ID,以及錢數

這個時候也許小伙伴們會問,應該也有問題吧:場景一:先扣款后發消息

先扣款再發送消息,萬一發送消息失敗了,那用戶B就沒法加錢

那把順序調整一下場景二:先發消息,后扣款

扣款成功消息發送成功,但用戶A扣款失敗,可加錢業務訂閱到了消息,用戶B加了錢

大家應該發現了問題所在,也就是沒法保證扣款和發送消息,同時成功,或同時失敗;導致數據不一致。

RocketMQ事務方案

因為上面的問題,RocketMq消息中間件把消息分為兩個階段Prepared階段確認階段Prepared階段(預備階段)

該階段主要發一個消息到rocketmq,但該消息只儲存在commitlog中但consumeQueue中不可見,也就是消費端(訂閱端)無法看到此消息

commit/rollback階段(確認階段)

該階段主要是把prepared消息保存到consumeQueue中,即讓消費端可以看到此消息,也就是可以消費此消息

?

?

我們用圖來說明下:

整個流程

1、在扣款之前,先發送預備消息
2、發送預備消息成功后,執行本地扣款事務
3、扣款成功后,再發送確認消息
4、消息端(加錢業務)可以看到確認消息,消費此消息,進行加錢

確認消息說明

注意:上面的確認消息可以為commit消息,可以被訂閱者消費;也可以是Rollback消息,即執行本地扣款事務失敗后,提交rollback消息,即刪除那個預備消息,訂閱者無法消費

我們來分析一下異常場景

異常1:如果發送預備消息失敗,下面的流程不會走下去;這個是正常的
異常2:
如果發送預備消息成功,但執行本地事務失敗;這個也沒有問題,因為此預備消息不會被消費端訂閱到,消費端不會執行業務。
異常3:
如果發送預備消息成功,執行本地事務成功,但發送確認消息失敗;這個就有問題了,因為用戶A扣款成功了,但加錢業務沒有訂閱到確認消息,無法加錢。這里出現了數據不一致。

那RocketMq是怎么解決的呢?

RocketMQ回查

image

RocketMq如何解決上面的問題,核心思路就是【狀態回查】,也就是RocketMq會定時遍歷commitlog中的預備消息。

因為預備消息最終肯定會變為commit消息或Rollback消息,所以遍歷預備消息去回查本地業務的執行狀態,如果發現本地業務沒有執行成功就rollBack,如果執行成功就發送commit消息。

上面的異常3,發送預備消息成功,本地扣款事務成功,但發送確認消息失敗;因為RocketMq會進行回查預備消息,在回查后發現業務已經扣款成功了,就補發“發送commit確認消息”;這樣加錢業務就可以訂閱此消息了。

這個思路其實把異常2也解決了,因為本地事務沒有執行成功,RocketMQ回查業務,發現沒有執行成功,就會發送RollBack確認消息,把消息進行刪除

回查判斷業務是否成功

小伙伴們在回查業務中,如何判斷本地事務是否執行成功

如果本地事務執行了很多張表,那是不是我們要把那些表都要進行判斷是否執行成功呢?這樣是不是太麻煩了,而且和業務很耦合。

有沒有更好的方式呢?就是設計一張Transaction表,將業務表和Transaction綁定在同一個本地事務中,如果扣款本地事務成功時,Transaction中應當已經記錄該TransactionId的狀態為「已完成」。當RocketMq回查時,只需要檢查對應的TransactionId的狀態是否是「已完成」就好,而不用關心具體的業務數據。



作者:消失er
鏈接:https://www.jianshu.com/p/286cac4625b6
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

總結

以上是生活随笔為你收集整理的RocketMQ的分布式事务解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。