tft每日頭條

 > 生活

 > rocketmq能解決分布式事務嗎

rocketmq能解決分布式事務嗎

生活 更新时间:2024-12-19 20:58:57

rocketmq能解決分布式事務嗎?之前提到發送消息的時候,可能存在消息的丢失,也就是說可能消息根本就沒有進入到MQ就丢了,然後沒有解釋過多的東西就直接切入了RocketMQ事務消息的方案,其實通過RocketMQ事務消息機制的研究,現在可以确信一點,如果使用事務消息機制去發送消息到MQ,一定是可以保證消息必然發送到MQ的,不會丢,我來為大家科普一下關于rocketmq能解決分布式事務嗎?下面希望有你要的答案,我們一起來看看吧!

rocketmq能解決分布式事務嗎(RocketMQ-解決發送消息零丢失一定要使用事務消息方案嗎)1

rocketmq能解決分布式事務嗎

之前提到發送消息的時候,可能存在消息的丢失,也就是說可能消息根本就沒有進入到MQ就丢了,然後沒有解釋過多的東西就直接切入了RocketMQ事務消息的方案,其實通過RocketMQ事務消息機制的研究,現在可以确信一點,如果使用事務消息機制去發送消息到MQ,一定是可以保證消息必然發送到MQ的,不會丢。

但是這個事務消息機制其實挺複雜的,先得發送half消息,然後還得發送rollback/commit的請求,要是中間有點什麼問題,MQ還得回調你的接口。

我們真的有必要使用這麼複雜的機制去确保消息到達MQ,而且絕對不會丢嗎?畢竟這麼複雜的機制完全有可能導緻整體性能比較差,而且吞吐量比較低,是否有更加簡單的方法來确保消息一定可以到達MQ呢?

能不能基于重試機制來确保消息到達MQ?

想到這裡,可能内心已經有一個想法了,就是我們之前覺得發消息到MQ,無非就是覺得可能半路上消息給丢失了,然後消息根本沒有進入到MQ中,我們也沒做什麼額外的措施,就導緻消息找不回來了。

那麼我們先搞清楚一個問題,我們發送消息到MQ,然後我們可以等待MQ返回響應給我們,在什麼樣的情況下,MQ會返回響應給我們呢?

答案是顯而易見的,就是MQ收到消息之後寫入本地磁盤文件了,當然這個時候可能僅僅是寫入os cache中,但是隻要他寫入自己本地存儲了,就會返回響應給我們。

那麼隻要我們在代碼中發送消息到MQ之後,同步等待MQ返回響應給我們,一直等待,如果半路有網絡異常或者MQ内部異常,我們肯定會收到一個異常,比如網絡錯誤,或者請求超時之類的。

如果我們再收到異常之後,就認為消息發送MQ失敗了,然後再次重試嘗試發送消息到MQ,接着再次同步等待MQ返回響應給我們,這樣反複重試,是否可以确保消息一定會到達MQ?

理論上似乎存在一些短暫網絡異常的場景下,我們是可以通過不停的重試去保證消息到達MQ的,因為如果短時間網絡異常了,消息一直沒法發送,我們隻要不停的重試,網絡一旦恢複了,消息就可以發送到MQ了。

如果要是反複重試多次發現一直沒有辦法把消息投遞到MQ,此時我們就可以直接讓訂單系統回滾之前的流程,判定本次訂單支付交易失敗了。

看起來這個簡單的同步發送消息 反複重試的方案,也可以做到保證消息一定可以投遞到MQ中。

但是如果是在比較複雜的訂單業務場景中,僅僅采用同步發消息 反複重試多次的方案去确保消息絕對投遞到MQ中,似乎還是不夠的。

先執行訂單本地事務,還是先發消息到MQ?

如果我們先執行本地事務,接着再發送消息到MQ,看起來僞代碼可能是這樣的:

try { // 執行訂單本地事務 orderService.finishOrderPay(); // 發送消息到MQ去 producer.sendMessage(); } catch (Exception e) { // 如果發送消息失敗了,進行重試 for(int i=0;i < 3; i ) { // 重試發送消息 } // 如果多次重試發送消息之後,還是不行 // 回滾本地訂單事務 orderService.rollbackOrderPay(); }

上面這段代碼看起來似乎天衣無縫,先執行訂單本地事務,接着發送消息到MQ,如果本地事務執行失敗了,則不會繼續發送消息到MQ了。

如果訂單事務執行成功了,發送MQ失敗了,自動進行幾次重試,重試如果一直失敗,就回滾訂單。

但是這裡有一個問題,假設你剛執行完訂單本地事務,結果還沒等到你發送消息到MQ,結果你的訂單系統突然崩潰了,這就導緻你的訂單狀态可能已經修改為了"已完成",但是消息卻沒有發送到MQ中去,這就是這個方案最大的隐患。

如果出現這種場景,那你的多次重試發送MQ之類的代碼根本沒有機會執行,而且訂單本地事務還已經執行成功了,你的消息還沒發送出去,消費者肯定沒有辦法消費。

把訂單本地事務和重試發送MQ消息放到一個事務代碼中

接着考慮下一個問題,這時候可能有一個新的想法,如果把訂單本地事務代碼和發送MQ消息的代碼放到一個事務代碼中呢?

@Transactional public void payOrderSuccess() { try { // 執行訂單本地事務 orderService.finishOrderPay(); // 發送消息到MQ去 producer.sendMessage(); } catch (Exception e) { // 如果發送消息失敗了,進行重試 for(int i=0;i < 3; i ) { // 重試發送消息 } // 如果多次重試發送消息之後,還是不行 // 抛出異常,回滾本地事務 throw new XXXException(); } }

上面這個代碼看起來似乎解決了我們的問題,就是在這個方法上加入事務,在這個事務方法中,我們哪怕執行了orderService.finishOrderPay(),但是其實也僅僅執行了一些增删改查的SQL語句,還沒提交訂單本地事務。

如果發送消息失敗了,而且多次重試還不奏效,則抛出異常會自動回滾本地事務。

如果你剛執行了 orderServicec.finishOrderPay(),結果訂單系統直接崩潰了,此時訂單本地事務會回滾,因為根本沒提交過。

但是對于這個方案,還是非常的不理想,原因就出在那個MQ多次重試的地方,假設用戶支付成功了,然後支付系統回調通知你的訂單系統說有一筆訂單支付成功了,這個時候你的訂單系統卡在多次重試MQ的代碼那裡,可能耗時了好幾秒中,此時回調通知及的系統早就等不及可能都超時異常了。

而且把重試MQ的代碼放在這個邏輯裡,可能導緻訂單系統的這個接口性能很差。

保證業務系統一緻性的最佳方案:基于RocketMQ的事務消息機制

綜合來看,真正要保證消息一定投遞到MQ,同時保證業務系統之間數據完全一緻,業内最佳的方案還是基于RocketMQ的事務消息機制。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved