ActiveMQ如何解決被重復消費和數據丟失的問題?


為什么要使用MQ?

1.解耦,系統A在代碼中直接調用系統B和系統C的代碼,如果將來D系統接入,系統A還需要修改代碼,過於麻煩!

2.異步,將消息寫入消息隊列,非必要的業務邏輯以異步的方式運行,加快響應速度

3.削峰,並發量大的時候,所有的請求直接懟到數據庫,造成數據庫連接異常

使用了消息隊列會有什么缺點?

1.系統可用性降低:你想啊,本來其他系統只要運行好好的,那你的系統就是正常的。現在你非要加個消息隊列進去,那消息隊列掛了,你的系統不是呵呵了。因此,系統可用性降低

2.系統復雜性增加:要多考慮很多方面的問題,比如一致性問題、如何保證消息不被重復消費,如何保證保證消息可靠傳輸。因此,需要考慮的東西更多,系統復雜性增大。

如何保證消息隊列是高可用的?

使用集群的方式維持MQ的可高用性。

如何保證消息不被重復消費?

保證消息不被重復消費的關鍵是保證消息隊列的冪等性,這個問題針對業務場景來答分以下幾點:

1.比如,你拿到這個消息做數據庫的insert操作。那就容易了,給這個消息做一個唯一主鍵,那么就算出現重復消費的情況,就會導致主鍵沖突,避免數據庫出現臟數據。

2.再比如,你拿到這個消息做redis的set的操作,那就容易了,不用解決,因為你無論set幾次結果都是一樣的,set操作本來就算冪等操作。

3.如果上面兩種情況還不行,上大招。准備一個第三方介質,來做消費記錄。以redis為例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。

如何解決丟數據的問題?

1.生產者丟數據

生產者的消息沒有投遞到MQ中怎么辦?從生產者弄丟數據這個角度來看,RabbitMQ提供transaction和confirm模式來確保生產者不丟消息。

transaction機制就是說,發送消息前,開啟事物(channel.txSelect()),然后發送消息,如果發送過程中出現什么異常,事物就會回滾(channel.txRollback()),如果發送成功則提交事物(channel.txCommit())。

然而缺點就是吞吐量下降了。因此,按照博主的經驗,生產上用confirm模式的居多。一旦channel進入confirm模式,所有在該信道上面發布的消息都將會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之后,rabbitMQ就會發送一個Ack給生產者(包含消息的唯一ID),這就使得生產者知道消息已經正確到達目的隊列了.如果rabiitMQ沒能處理該消息,則會發送一個Nack消息給你,你可以進行重試操作。

2.消息隊列丟數據

處理消息隊列丟數據的情況,一般是開啟持久化磁盤的配置。這個持久化配置可以和confirm機制配合使用,你可以在消息持久化磁盤后,再給生產者發送一個Ack信號。這樣,如果消息持久化磁盤之前,rabbitMQ陣亡了,那么生產者收不到Ack信號,生產者會自動重發。

那么如何持久化呢,這里順便說一下吧,其實也很容易,就下面兩步

①、將queue的持久化標識durable設置為true,則代表是一個持久的隊列

②、發送消息的時候將deliveryMode=2

這樣設置以后,rabbitMQ就算掛了,重啟后也能恢復數據。在消息還沒有持久化到硬盤時,可能服務已經死掉,這種情況可以通過引入mirrored-queue即鏡像隊列,但也不能保證消息百分百不丟失(整個集群都掛掉)

3.消費者丟數據

啟用手動確認模式可以解決這個問題

①自動確認模式,消費者掛掉,待ack的消息回歸到隊列中。消費者拋出異常,消息會不斷的被重發,直到處理成功。不會丟失消息,即便服務掛掉,沒有處理完成的消息會重回隊列,但是異常會讓消息不斷重試。

②手動確認模式,如果消費者來不及處理就死掉時,沒有響應ack時會重復發送一條信息給其他消費者;如果監聽程序處理異常了,且未對異常進行捕獲,會一直重復接收消息,然后一直拋異常;如果對異常進行了捕獲,但是沒有在finally里ack,也會一直重復發送消息(重試機制)。

③不確認模式,acknowledge="none" 不使用確認機制,只要消息發送完成會立即在隊列移除,無論客戶端異常還是斷開,只要發送完就移除,不會重發。

如何保證消息的順序性?

針對這個問題,通過某種算法,將需要保持先后順序的消息放到同一個消息隊列中。然后只用一個消費者去消費該隊列。同一個queue里的消息一定是順序消息的。我的觀點是保證入隊有序就行,出隊以后的順序交給消費者自己去保證,沒有固定套路。例如B消息的業務應該保證在A消息后業務后執行,那么我們保證A消息先進queueA,B消息后進queueB就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM