RabbitMQ的幾個常見問題


1. 如何保證消息盡量發送成功?

問題描述: 如果沒有啟動消費者,重啟了RabbitMQ服務,隊列和消息都會丟失。

解決方案: 針對這個問題,有以下幾個機制可以解決:

  1. 生產者確認;
  2. 持久化;
  3. 手動ACK。

生產者確認

首先,我們要確保生產者能成功地將消息發送到RabbitMQ服務器。
默認情況下生產者發送消息並不會返回任何狀態信息,也就是它並不知道消息有沒有正確地到達服務器。

針對這個問題,RabbitMQ提供了兩種解決方案:

  1. 事務機制;
  2. 通過發送方確認機制(publisher confirm);

事務機制相關的方法主要有三個:

  1. channel.txSelect:用於將當前的channel設置成事務模式;
  2. channel.txCommit:用於提交事務;
  3. channel.txRollback:用於回滾事務.

用過數據庫的人對事務一詞肯定不陌生,在RabbitMQ中也是類似的,只有消息被RabbitMQ服務端成功接收,事務才能提交成功,否則就會觸發異常,可以對異常進行捕獲處理。
事務機制是阻塞形式的,一條消息發送之后會使消息端阻塞,以等待RabbitMQ的回應,才能發送下一個消息。
使用事務機制會影響RabbitMQ的性能,因此還是推薦使用發送方確認機制。

發送方確認機制是指生產者將channel設置成confirm模式,所有在該信道上發布的消息都會被指派一個唯一ID(從1開始),一旦消息被投遞到RabbitMQ服務器之后,RabbitMQ就會發送一個包含了消息唯一ID的確認(Basic.Ack)給生產者,使生產者知道消息已經正確到達了目的地。
如果RabbitMQ因為內部錯誤導致消息丟失,就會發送一條nack(Basic.Nack)命令,生產者可以在回調方法中處理該nack命令。
發送方確認機制是異步的,一旦發布一條消息,生產者可以在等待信道返回的同時發送下一條消息,當消息確認時,可以在回調方法中處理該確認消息。因此,總體效率會更好。
相關的方法:

  1. channel.confirmSelect();
  2. channel.waitForConfirms;
  3. channel.addConfirmListener;

當然confirm機制也可以分為:普通confirm,批量confirm,異步confirm。
普通confirm可事務機制差不多,就是發送一條,就調用waitForConfirms確認一次;批量confirm就是發送多條后,再調用waitForConfirms確認一次;異步confirm就是注冊兩個回調分別處理Ack和NAck確認。

事務機制和生產者確認機制是互斥的,不能共存!

發送成功的含義是消息能到達RabbitMQ交換機,並且能有匹配的隊列接收。

總體效率上,異步confirm會更好。

2. 如何進行消息持久化?

所謂持久化,就是RabbitMQ將內存中的數據(比如交換機、隊列、消息等)固化到磁盤,以防止異常情況的發生時造成數據丟失。

RabbitMQ持久化分為:

  1. 交換機持久化;
  2. 隊列持久化;
  3. 消息持久化

交換機的持久化

在創建Exchange時設置durable參數參數。

channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);

隊列的持久化

同樣也是設置設置durable參數。
持久化的隊列會存盤,在服務器重啟的時候可以保證不丟失相關信息。

channel.queueDeclare(QUEUE_NAME, true, false, false, null);

消息的持久化

即使交換機、隊列持久化不會因為重啟丟失,但是存儲在隊列中的消息仍然會丟失。
解決的辦法就是設置消息的投遞模式為2,即代表持久化(JAVA)。

理論上,可以將所有的消息都設置為持久化,但是這會嚴重影響RabbitMQ性能,因為寫入到磁盤的速度可比寫入到內存的速度慢非常多。因此,在選擇是否要持久化消息時,需要在可靠性和吞吐量之間做一個權衡。

然而,將交換機、隊列、消息都設置持久化之后仍然不能夠保證百分百不會丟失數據。因為有些消息可能還沒來得及落盤,就發生了宕機、重啟等異常情況。

如何保證消息被正確消費

這部分要處理的場景是: 當消費者接收到消息后,還沒處理完業務邏輯,消費者掛掉了,此時消息等同於丟失了。

為了確保消息被消費者成功消費,RabbitMQ提供了消息確認機制,主要通過顯示Ack模式來實現。

默認情況下,RabbitMQ會自動把發送出去的消息置為確認,然后從內存(或磁盤)刪除,但是我們在使用時可以手動設置autoAck為False的,當然具體做法各個語言都不一樣。

需要注意的時,如果設置autoAck為false,也就意味者每條消息需要我們自己發送ack確認,RabbitMQ才能正確標識消息的狀態。

消息隊列的優缺點

優點:

  1. 解耦和復用,易擴展;
  2. 異步;
  3. 削峰;

缺點:

  1. 系統可用性降低,復雜度提高,mq要是掛了,影響太大;
  2. 存在數據一致性問題

選用RabbitMQ的理由

目前還是有很多種消息隊列的,各有特點。
對於選用RabbitMQ的理由,大概因為:延時低是它最大的特點,同時單機吞吐量也很不錯;也能進行分布式集群擴展;社區非常活躍。


免責聲明!

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



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