消息隊列】RabbitMQ如何處理消息丟失

首先明確一點 一條消息的傳送流程:生產者->MQ->消費者

所以有三個地方都會丟失數據:

生產者發送給MQ的途中出現網絡問題
MQ自己沒保管好弄丟了
消費者拿到數據後出錯了沒有最終完成任務
依次分析

1)生產者弄丟了數據

生產者將數據發送到rabbitmq的時候,可能因爲網絡問題導致數據就在半路給搞丟了。

1.使用事務(性能差)
可以選擇用rabbitmq提供的事務功能,在生產者發送數據之前開啓rabbitmq事務(channel.txSelect),然後發送消息,如果消息沒有成功被rabbitmq接收到,那麼生產者會收到異常報錯,此時就可以回滾事務(channel.txRollback),然後重試發送消息;如果收到了消息,那麼可以提交事務(channel.txCommit)。但是問題是,開始rabbitmq事務機制,基本上吞吐量會下來,因爲太耗性能。

2.發送回執確認(推薦)
可以開啓confirm模式,在生產者那裏設置開啓confirm模式之後,你每次寫的消息都會分配一個唯一的id,然後如果寫入了rabbitmq中,rabbitmq會給你回傳一個ack消息,告訴你說這個消息ok了。如果rabbitmq沒能處理這個消息,會回調你一個nack接口,告訴你這個消息接收失敗,你可以重試。而且你可以結合這個機制自己在內存裏維護每個消息id的狀態,如果超過一定時間還沒接收到這個消息的回調,那麼你可以重發。
  事務機制和cnofirm機制最大的不同在於,事務機制是同步的,你提交一個事務之後會阻塞在那兒,但是confirm機制是異步的,你發送個消息之後就可以發送下一個消息,然後那個消息rabbitmq接收了之後會異步回調你一個接口通知你這個消息接收到了。

所以一般在生產者這塊避免數據丟失,都是用confirm機制的。

2)RabbitMQ弄丟了數據-開啓RabbitMQ的數據持久化

爲了防止rabbitmq自己弄丟了數據,這個你必須開啓rabbitmq的持久化,就是消息寫入之後會持久化到磁盤,哪怕是rabbitmq自己掛了,恢復之後會自動讀取之前存儲的數據,一般數據不會丟。除非極其罕見的是,rabbitmq還沒持久化,自己就掛了,可能導致少量數據會丟失的,但是這個概率較小。

設置持久化有兩個步驟,第一個是創建queue的時候將其設置爲持久化的,這樣就可以保證rabbitmq持久化queue的元數據,但是不會持久化queue裏的數據;第二個是發送消息的時候將消息的deliveryMode設置爲2,就是將消息設置爲持久化的,此時rabbitmq就會將消息持久化到磁盤上去。必須要同時設置這兩個持久化纔行,rabbitmq哪怕是掛了,再次重啓,也會從磁盤上重啓恢復queue,恢復這個queue裏的數據。

而且持久化可以跟生產者那邊的confirm機制配合起來,只有消息被持久化到磁盤之後,纔會通知生產者ack了,所以哪怕是在持久化到磁盤之前,rabbitmq掛了,數據丟了,生產者收不到ack,你也是可以自己重發的。

若生產者那邊的confirm機制未開啓的情況下,哪怕是你給rabbitmq開啓了持久化機制,也有一種可能,就是這個消息寫到了rabbitmq中,但是還沒來得及持久化到磁盤上,結果不巧,此時rabbitmq掛了,就會導致內存裏的一點點數據會丟失。

3)消費端弄丟了數據

主要是因爲你消費的時候,剛消費到,還沒處理,結果進程掛了比如重啓了,那麼就尷尬了,RabbitMQ認爲你都消費了,這數據就丟了。或者消費者拿到數據之後掛了,這時候需要MQ重新指派另一個消費者去執行任務(一塊肉,剛用筷子夾起來,發地震抖了一下,肉掉了)

這個時候得用RabbitMQ提供的ack機制,也是一種處理完成發送回執確認的機制。如果MQ等待一段時間後你沒有發送過來處理完成 那麼RabbitMQ就認爲你還沒處理完,這個時候RabbitMQ會把這個消費分配給別的consumer去處理,消息是不會丟的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章