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的性能,所以仍是推薦使用發送方確認機制。spa

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

  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的理由,大概由於:延時低是它最大的特色,同時單機吞吐量也很不錯;也能進行分佈式集羣擴展;社區很是活躍。

相關文章
相關標籤/搜索