RabbitMQ(三)保證消息的可靠性傳輸

一、Rabbit如何保證消息的可靠性傳輸(如何處理消息丟失的問題)?

1、生產者弄丟了數據(事務、confirm)

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

此時可以選擇用RabbitMQ提供的事務功能,就是生產者發送數據之前開啓RabbitMQ事務channel.txSelect,然後發送消息,如果消息沒有成功被RabbitMQ接收到,那麼生產者會收到異常報錯,此時就可以回滾事務channel.txRollback,然後重試發送消息;如果收到了消息,那麼可以提交事務channel.txCommit。

但是問題是,RabbitMQ事務機制(同步)一搞,基本上吞吐量會下來,因爲太耗性能

所以一般來說,如果你要確保說寫RabbitMQ的消息別丟,可以開啓 confirm模式,在生產者那裏設置開啓confirm模式之後,你每次寫的消息都會分配一個唯一的id,然後如果寫入了 RabbitMQ 中,RabbitMQ 會給你回傳一個 ack消息,告訴你說這個消息ok了。如果 RabbitMQ 沒能處理這個消息,會回調你的一個 nack接口,告訴你這個消息接收失敗,你可以重試。而且你可以結合這個機制自己在內存裏維護每個消息id的狀態,如果超過一定時間還沒接收到這個消息的回調,那麼你可以重發。

事務機制和confirm機制最大的不同在於:

  • 事務機制同步的,你提交一個事務之後會阻塞在那兒
  • confirm機制異步的,你發送個消息之後就可以發送下一個消息,然後那個消息RabbitMQ接收了之後會異步回調你的一個接口通知你這個消息接收到了。

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

 

2、RabbitMQ 弄丟了數據(持久化)

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

設置持久化有兩個步驟:

(1)創建 queue 的時候將其設置爲持久化

這樣就可以保證 RabbitMQ 持久化 queue 的元數據,但是它是不會持久化 queue 裏的數據的。

(2)第二個是發送消息的時候將消息的 deliveryMode 設置爲 2

就是將消息設置爲持久化的,此時 RabbitMQ 就會將消息持久化到磁盤上去。

必須要同時設置這兩個持久化纔行,RabbitMQ 哪怕是掛了,再次重啓,也會從磁盤上重啓恢復 queue,恢復這個 queue 裏的數據。

注意,哪怕是你給 RabbitMQ 開啓了持久化機制,也有一種可能,就是這個消息寫到了 RabbitMQ 中,但是還沒來得及持久化到磁盤上,結果不巧,此時 RabbitMQ 掛了,就會導致內存裏的一點點數據丟失。

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

 

3、消費端弄丟了數據(ack機制)

RabbitMQ如果丟失了數據,主要是因爲你消費的時候,剛消費到,還沒處理,結果進程掛了,比如重啓了,那麼就尷尬了,RabbitMQ認爲你都消費了,這數據就丟了。

這個時候得用RabbitMQ提供的 ack機制,簡單來說,就是你必須關閉RabbitMQ的自動 ack,可以通過一個api來調用就行,然後每次你自己代碼裏確保處理完的時候,再在程序裏 ack一把。這樣的話,如果你還沒處理完,不就沒有ack了?那RabbitMQ就認爲你還沒處理完,這個時候 RabbitMQ 會把這個消費分配給別的 consumer 去處理,消息是不會丟的。

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