1. 程式人生 > >如何保證訊息的可靠性傳輸(如何處理訊息丟失的問題)

如何保證訊息的可靠性傳輸(如何處理訊息丟失的問題)

RabbitMQ

 

生產者弄丟了資料  

  生產者將資料傳送到RabbitMQ的時候,可能資料就在半路給搞丟了,因為網路啥的問題,都有可能。  

  此時可以選擇用RabbitMQ提供的事務功能,就是生產者傳送資料之前開啟RabbitMQ事務(channel.txSelect),然後傳送訊息,如果訊息沒有成功被RabbitMQ接收到,那麼生產者會收到異常報錯,此時就可以回滾事務(channel.txRollback),然後重試傳送訊息;如果收到了訊息,那麼可以提交事務(channel.txCommit)。這種方式會降低吞吐量,影響效能。

  還有一種方式是開啟confirm模式

,在生產者那裡設定開啟confirm模式之後,你每次寫的訊息都會分配一個唯一的id,然後如果寫入了RabbitMQ中,RabbitMQ會給你回傳一個ack訊息,告訴你說這個訊息ok了。如果RabbitMQ沒能處理這個訊息,會回撥你一個nack介面,告訴你這個訊息接收失敗,你可以重試。而且你可以結合這個機制自己在記憶體裡維護每個訊息id的狀態,如果超過一定時間還沒接收到這個訊息的回撥,那麼你可以重發。  

  事務機制和cnofirm機制最大的不同在於,事務機制是同步的,你提交一個事務之後會阻塞在那兒,但是confirm機制是非同步的,你傳送個訊息之後就可以傳送下一個訊息,然後那個訊息RabbitMQ接收了之後會非同步回撥你一個介面通知你這個訊息接收到了。   所以一般在生產者這塊避免資料丟失,都是用confirm機制的。

 

RabbitMQ弄丟了資料  

  就是RabbitMQ自己弄丟了資料,這個你必須開啟RabbitMQ的持久化,訊息寫入之後會持久化到磁碟,哪怕是RabbitMQ自己掛了,恢復之後會自動讀取之前儲存的資料,一般資料不會丟。

  除非極其罕見的是,RabbitMQ還沒持久化,自己就掛了,可能導致少量資料會丟失的,但是這個概率較小。  

  設定持久化有兩個步驟,第一個是建立queue的時候將其設定為持久化的,這樣就可以保證RabbitMQ持久化queue的元資料,但是不會持久化queue裡的資料;

  第二個是傳送訊息的時候將訊息的deliveryMode設定為2,就是將訊息設定為持久化的,此時RabbitMQ就會將訊息持久化到磁碟上去。

  必須要同時設定這兩個持久化才行,RabbitMQ哪怕是掛了,再次重啟,也會從磁碟上重啟恢復queue,恢復這個queue裡的資料。  

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

  給RabbitMQ開啟了持久化機制後,也還有一種可能,就是這個訊息寫到了RabbitMQ中,但是還沒來得及持久化到磁碟上,結果不巧,此時RabbitMQ掛了,就會導致記憶體裡的一點點資料會丟失。

 

消費端弄丟了資料  

  消費的時候,剛消費到,還沒處理,結果程序掛了,比如重啟了,RabbitMQ認為你都消費了,這資料就丟了。  

  這個時候得用RabbitMQ提供的ack機制,簡單來說,就是你關閉RabbitMQ自動ack,可以通過一個api來呼叫就行,然後每次你自己程式碼裡確保處理完的時候,再程式裡ack一把。

  這樣的話,如果你還沒處理完,不就沒有ack?那RabbitMQ就認為你還沒處理完,這個時候RabbitMQ會把這個消費分配給別的consumer去處理,訊息是不會丟的。