如何保證RabbitMQ的消息不丟失及其背后的原理


一、消息為什么丟失

RabbitMQ默認情況下的交換機和隊列以及消息是非持久化的,也就是說在服務器重啟或者宕機恢復后,之前創建的交換機和隊列都將不復存在,之前未消費的消息也就消失不見了。原因在於每個隊列和交換機的durable屬性。該屬性默認情況是false,它決定了RabbitMQ是否需要在崩潰或者重啟之后重新創建隊列(或者交換機)。

二、持久化交換機和隊列

將交換機和隊列的durable屬性設置為true,這樣你就不需要在服務器斷電后重新創建隊列和交換機了。你也許會認為把隊列和交換機的durable屬性設置為true就足夠可以讓消息幸免於重啟后丟失了,真的是這樣嗎?隊列和交換機當然必須被設置為true,但光這樣做還不夠。
能從AMQP服務器崩潰中恢復的消息,我們稱之為持久化消息。在消息發布前,通過把它的“投遞默認”( delivery mode)選項設置為2(AMQP客戶端可能會使用人性化的常量來代替數值)來把消息標記成持久化。到目前為止,消息還只是被表示為持久化的,但是它還必須被發布到持久化的交換機中,並到達持久化的隊列中才行。如果不是這樣的話,則包含持久化消息的隊列(或者交換機)會在Rabbit崩潰重啟后不復存在,從而導致消息丟失。

三、持久化消息

因此,如果消息想要從Rabbit崩潰中恢復,那么消息必須滿足以下條件:
1. 把它的投遞默認選項設置為持久化
2. 發送到持久化的交換機
3. 到達持久化的隊列

做到以上三點,你就不需要擔心發送到Rabbit服務器的消息因服務器崩潰等其它原因而丟失了。

四、如何做到消息持久化的

RabbitMQ確保持久性消息能從服務器重啟中恢復的方式是,將它們寫入磁盤上的一個持久化日志文件。當發布一個持久性消息到持久交換機上時,Rabbit會在消息提交到日志文件后才發送響應。記住,之后這條消息如果路由到了非持久隊列的話,它會自動從持久性日志中移除,並且無法從服務器重啟中恢復。如果你使用持久性消息的話,則確保之前提到的持久性消息的那三點都必須做到位。一旦你從持久性隊列中消費了一個持久性消息的話(並且確認了它),RabbitMQ會在持久化日志中把這條消息標記為等待垃圾收集。在你消費持久性消息前,如果RabbitMQ重啟的話,服務器會自動重建交換機和隊列(以及綁定),重播持久性日志文件的消息到合適的隊列或者交換機上(取決於Rabbit服務器宕機的時候,消息處在路由過程的哪個環節)。

雖然持久化消息可以做到消息的不丟失,但持久化的消息在進入隊列前會被寫到磁盤,這個過程比寫到內存慢得多,所以會嚴重的影響性能,可能導致消息的吞吐量降低10倍不止。所以,在做消息持久化前,一定要認真考慮性能和需求之間的平衡關系。


免責聲明!

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



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