中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

構建基于RocketMQ的分布式事務服務

發布時間:2020-07-01 16:56:14 來源:網絡 閱讀:4836 作者:艾瑞克博客 欄目:建站服務器

說在前面

Apache RocketMQ-4.3.0正式Release了事務消息的特性,順著最近的這個熱點。第一篇文章,就來聊一下在軟件工程學上的長久的難題——分布式事務(Distributed Transaction)。

這個技術也在各個諸如阿里,騰訊等大廠的內部,被廣泛地實現,利用及優化。但是由于理論上就有難點,所以分布式事務就隱晦得成了大廠對于小廠的技術壁壘。相信來看這篇文章的同學,一定都聽過很多關于分布式事務的術語,比較二階段提交,TCC,最終一致性等,所以這里也不多普及概念。

基于RocketMQ的分布式事務

我們直接上正題,利用RocketMQ設計自己的分布式事務組件。

舉個虛擬場景引出問題

用戶從農行轉賬100元去招行?,農行的系統和招行的系統分別部署在自己的機房,系統之間通過消息進行通信,防止過度耦合。

整個模型可以不恰當得描述為:農行扣了100元后,發送“已經扣款”的消息給招行,招行收到消息,知道農行扣款成功了,然后在招行賬戶上加100元。

問題是,農行這邊,方案1. 先扣100元再發消息,方案2. 先發消息再扣100元

整理下整個事務不一致的場景:

方案1,

農行扣100后成功,但是消息發送失敗,招行沒有加100

方案2,

消息發送成功,但是農行扣100元失敗,招行收到消息加了100

各位同學應該已經發現問題所在了,扣款和發送消息這兩個事情,沒有辦法通過調換順序實現「同時成功」,或者「同時失敗。如果前者成功,后者失敗,就會造成不一致。

RocketMQ,以下簡稱RMQ,為了實現事務消息引入了一種新的消息類型:TransactionMsg

一個完整的事務消息分成兩個部分:

HalfMsg(Prepare)?+?Commit/RollbackMsg

Producer發送了HalfMsg后,由于HalfMsg不是一個完整的事務消息,Consumer無法立刻就消費到該消息,Producer可以對HalfMsg進行Commit或者Rollback來終結事務(EndTransacaction)。只有當Commit了HalfMsg后,Consumer才能消費到這條消息。RMQ會定期去向Producer詢問,是否可以Commit或者Rollback那些由于錯誤沒有被終結的HalfMsg來結束它們的生命周期,以達成事務最終的一致。

依然是剛剛的轉賬場景,我們用RMQ事務消息來優化下流程:

  1. 農行向RMQ同步發送HalfMsg,消息中攜帶農行即將要扣100元的信息

  2. 農行HalfMsg成功發送后,執行數據庫本地事務,在自己的系統中扣100元

  3. 農行查看本地事務執行情況

  4. 本地事務返回成功,農行向RMQ提交(Commit)HalfMsg

  5. 招行系統訂閱了RMQ,順利收到農行已經扣款100元的信息

  6. 招行系統執行本地事務,在招行的系統中加100元

構建基于RocketMQ的分布式事務服務cdn.xitu.io/2018/9/26/166159d6de987c5e?w=1080&h=834&f=jpeg&s=49401">

構建基于RocketMQ的分布式事務服務

圖1:RMQ事務消息原理

同樣得,我們逐個來分析下這個流程是不是會出現不一致:

  1. 農行發送HalfMsg是同步發送(Sync),如果HalfMsg發送不成功,壓根就不會執行本地事務

  2. 發送HalfMsg成功,但是農行扣款**本地事務失敗,也沒事,如果本地事務沒有成功,立刻就發送Rollback去回滾HalfMsg**。就當之前啥事都沒有發生過

  3. 農行本地事務成功了,但是Commit卻失敗了,但是由于HalfMsg已經在RMQ中,RMQ就能通過定時程序讓農行重新檢測本地事務是否成功重新Commit。Rollback失敗了也是同理

  4. 招行消費了消息后,加錢本地事務失敗了,但是招行收到的消息持久化在MQ,甚至可以持久化在招行數據庫,可以進行事務重試

剛剛討論的案例是非常理想化的,整個分布式事務中,只涉及到了金額的變化,但是,真正的線上系統,作為消息發送方的本地事務可能就非常復雜,可能涉及到了幾十張不同的表,那RMQ用定時器來Check HalfMsg,難道去查下涉及該事務的每一張表的數據是否提交成功?顯然這種方案非常業務侵入非常大,并且很難組件化。所以需要在本地事務中設計一張Transaction表,將業務表和Transaction綁定在同一個本地事務中,如果農行的扣款本地事務成功時,Transaction中應當已經記錄該TransactionId的狀態為「已完成」。當最后需要檢查時,只需要檢查對應的TransactionId的狀態是否是「已完成」就好,而不用關心具體的業務數據。

再談一個小細節,

細心的同學可能發現,剛剛No.3的討論其實是有點不嚴謹的,RMQ在調用Commit或者Rollback時,用的是Oneway的方式,熟悉RMQ源碼的話,知道這種網絡調用是只單向發送Request,不會去獲取Response消息發送性能上是有非常大的提升的,但是如果真的發送失敗,Producer是不會知曉的,最后只能通過定時檢查HalfMsg才能終結事務

public void endTransactionOneway(
        final String addr,
        final EndTransactionRequestHeader requestHeader,
        final String remark,
        final long timeoutMillis
    ) throws RemotingException, MQBrokerException, InterruptedException {
        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, requestHeader);

        request.setRemark(remark);
        // 使用Oneway發送end transaction類型的
        this.remotingClient.invokeOneway(addr, request, timeoutMillis);
    }

脫離RocketMQ的分布式事務

不是所有的MQ都能支持事務消息,如何使用一般的MQ來搭建分布式事務組件,甚至抽象成一個事務SOA服務?

其實仔細分析下RMQ的事務消息,我們可以把它拆解成兩個部分:

事務管理器?+?消息

所謂的事務管理器,就是對于事務的預備(Prepare)提交(Commit)回滾(Rollback)的管理,另外還包含預備事務的定時檢查器

消息,指的就是一般的同步消息,發送后能明確得到發送結果,用于事務系統與業務系統解耦。幾乎所有的分布式MQ都是支持這種消息的。

我們來設計下自己的DistributedTransaction SOA,以下簡稱DT-SOA

構建基于RocketMQ的分布式事務服務

構建基于RocketMQ的分布式事務服務

圖2:分布式事務服務化

流程還是沒有變,但分布式事務不再強依賴RMQ,而是用一般的MQ代替:

  1. 系統A發送事務,首先調用DT-SOA的Prepare方法準備開啟事務,由于是同步調用,獲取SendResult,如果發送成功,拿到全局分布式事務的ID——TID

  2. 系統A用獲取到的TID執行本地事務,本地事務中包含Transaction狀態表,成功后將TID對應的狀態置為“已完成”

  3. 系統A調用DT-SOA提交事務,DT-SOA用MQ發送同步消息給系統B

  4. 系統B監聽對應Topic,接收到消息后,執行對應的本地事務

說在后面

更多精彩的文章,請關注我的微信公眾號: 艾瑞克的技術江湖
構建基于RocketMQ的分布式事務服務

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿巴嘎旗| 福鼎市| 梧州市| 汉川市| 江达县| 丰台区| 石楼县| 慈溪市| 乌拉特后旗| 罗山县| 九龙城区| 湖南省| 太仓市| 珠海市| 保德县| 赞皇县| 福州市| 海阳市| 金沙县| 石柱| 和龙市| 儋州市| 剑阁县| 陇川县| 纳雍县| 阿图什市| 镇原县| 潢川县| 巴塘县| 鄂尔多斯市| 岳阳市| 鄂伦春自治旗| 和龙市| 江西省| 盖州市| 阿坝| 湖北省| 玉田县| 安义县| 壤塘县| 定陶县|