RocketMQ訊息丟失解決方案:同步刷盤+手動提交

王子發表於2020-10-28

 

前言

之前我們一起了解了使用RocketMQ事務訊息解決生產者傳送訊息時訊息丟失的問題,但使用了事務訊息後訊息就一定不會丟失了嗎,肯定是不能保證的。

因為雖然我們解決了生產者傳送訊息時候的訊息丟失問題,但也只是保證Broker正確的接收到了訊息,實際上接收到的訊息會儲存在os cache中,如果此時broker機器突然當機,os cache中的訊息資料就丟失掉了。

而且就算是os cache中的訊息已經刷盤到了磁碟中,如果磁碟突然就壞了,訊息是不是也就丟失了。

所以我們還要考慮Broker如何保證訊息不丟失。

 

Broker的訊息丟失解決方案

說到這裡,我們就進入主題了,首先解決臨時存在os cache,而未重新整理到磁碟導致的訊息丟失問題,那麼如何解決呢?

看過之前系列文章的小夥伴都知道,Broker是有兩種刷盤機制的,同步刷盤和非同步刷盤,詳細內容可以回顧一下這篇文章:深入研究Broker是如何持久化的

解決的方式就是把非同步刷盤改為同步刷盤,具體操作就是修改一下broker的配置檔案,將其中的flushDiskType配置設定為:SYNC_FLUSH,預設它的值是ASYNC_FLUSH,即非同步刷盤。

調整為同步刷盤後,只要MQ告訴我們訊息傳送成功了,那麼就說明訊息已經在磁碟中了。

接下來就要解決磁碟壞了導致的訊息丟失問題了。

這個問題其實也很好解決,只要我們使用RockerMQ的高可用叢集模式就可以了,也就是說如果返回訊息傳送成功的響應,那就代表Master Broker已經把資料同步到了Slave Broker中,保證資料有多個備份。

這樣一來就算是Master Broker突然當機 ,也可以通過Dledger技術進行主從的自動切換,使用我們備份的資料,這其中的原理我們已經講過了,小夥伴們可以自己去複習回顧一下。Dledger是如何實現主從自動切換的

 

Consumer的訊息丟失解決方案

到這裡,我們已經確保了生產者和Broker的訊息不會丟失了,那麼消費者處理訊息的時候會不會導致訊息丟失呢?

答案是肯定的。

比如說我們的積分系統拿到了訊息,還未執行該執行的操作,先返回給broker這條訊息的offset,說這條訊息已經處理過了。然後突然當機了,這就導致mq認為這條訊息已經處理過了,而實際並沒有處理,所以這條訊息就丟失掉了。

對於Kafka和RabbitMQ來講,預設的消費模式就是上邊這種自動提交的模式,所以是有可能導致訊息丟失掉的。

而RocketMQ的消費者有點不一樣,它本身就是需要手動返回訊息處理成功的響應的。

所以其實Consumer的訊息丟失解決方案也很簡單,就是將自動提交改為手動提交

 

訊息零丟失方案的優缺點分析

如果在系統中落地一套訊息零丟失的方案,無論什麼場景都保證訊息的可靠性,這似乎聽起來不錯,這也是它的優點所在,保證系統的資料都是正確的,不會有丟失的情況。

但它有什麼缺點呢?

首先,引入了這套解決方案之後,系統的複雜度變高了,想想事務訊息的實現方式你肯定會這麼覺得。

而且比較嚴重的缺點是,它會導致系統的效能嚴重的下降,比如原來每秒可以處理好幾萬條的訊息,結果在引入訊息零丟失這套方案之後,可能每秒就只能處理幾千條訊息了。

其實只要隨便思考一下,就可以想明白這個問題。

事務訊息的複雜性導致生產訊息的過程耗時更久了,同步刷盤的策略導致寫入磁碟後才返回訊息,自然也會增加耗時,而消費者如果非同步的處理訊息,直接返回成功,整個流程的速度會更快。

所以說引入這麼一套訊息零丟失的方案,對於效能的影響還是很大的。

 

 

總結

其實關於訊息零丟失的方案無外乎就這麼多,所以本篇文章內容不是很多。

既然我們剛才聊了訊息零丟失方案的缺點,那麼就繼續討論一下,究竟什麼場景下需要引入這套方案吧。

王子給大家介紹一下自己的想法。

一般我們對於跟金錢、交易以及核心資料相關的系統和核心鏈路,可以採用這套方案。

比如說我們文章中舉的例子:支付系統、訂單系統、積分系統。

而對於其他的沒那麼核心的場景,丟失一些資料問題也不大,就不應該採用這套方案了,或者說可以做一些簡化,比如事務訊息改成失敗重試幾次的機制,刷盤策略改為非同步刷盤。

那麼小夥伴們在平時的工作中,這套方案是怎麼應用到生產環境中的呢?歡迎留言討論。

 

 

往期文章推薦:

深入研究RocketMQ生產者傳送訊息的底層原理

深入研究Broker是如何持久化的

Dledger是如何實現主從自動切換的

深入研究RocketMQ消費者是如何獲取訊息的

RocketMQ的訊息是怎麼丟失的

RocketMQ訊息丟失解決方案:事務訊息

 

相關文章