問題描述: 若是沒有啓動消費者,重啓了RabbitMQ服務,隊列和消息都會丟失。數據庫
解決方案: 針對這個問題,有如下幾個機制能夠解決:服務器
首先,咱們要確保生產者能成功地將消息發送到RabbitMQ服務器。
默認狀況下生產者發送消息並不會返回任何狀態信息,也就是它並不知道消息有沒有正確地到達服務器。異步
針對這個問題,RabbitMQ提供了兩種解決方案:分佈式
事務機制相關的方法主要有三個:性能
用過數據庫的人對事務一詞確定不陌生,在RabbitMQ中也是相似的,只有消息被RabbitMQ服務端成功接收,事務才能提交成功,不然就會觸發異常,能夠對異常進行捕獲處理。 事務機制是阻塞形式的,一條消息發送以後會使消息端阻塞,以等待RabbitMQ的迴應,才能發送下一個消息。 使用事務機制會影響RabbitMQ的性能,所以仍是推薦使用發送方確認機制。spa
發送方確認機制是指生產者將channel設置成confirm模式,全部在該信道上發佈的消息都會被指派一個惟一ID(從1開始),一旦消息被投遞到RabbitMQ服務器以後,RabbitMQ就會發送一個包含了消息惟一ID的確認(Basic.Ack)給生產者,使生產者知道消息已經正確到達了目的地。
若是RabbitMQ由於內部錯誤致使消息丟失,就會發送一條nack(Basic.Nack)命令,生產者能夠在回調方法中處理該nack命令。
發送方確認機制是異步的,一旦發佈一條消息,生產者能夠在等待信道返回的同時發送下一條消息,當消息確認時,能夠在回調方法中處理該確認消息。所以,整體效率會更好。
相關的方法:code
固然confirm機制也能夠分爲:普通confirm,批量confirm,異步confirm。
普通confirm可事務機制差很少,就是發送一條,就調用waitForConfirms確認一次;批量confirm就是發送多條後,再調用waitForConfirms確認一次;異步confirm就是註冊兩個回調分別處理Ack和NAck確認。隊列
事務機制和生產者確認機制是互斥的,不能共存!事務
發送成功的含義是消息能到達RabbitMQ交換機,而且能有匹配的隊列接收。內存
整體效率上,異步confirm會更好。
所謂持久化,就是RabbitMQ將內存中的數據(好比交換機、隊列、消息等)固化到磁盤,以防止異常狀況的發生時形成數據丟失。
RabbitMQ持久化分爲:
在建立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才能正確標識消息的狀態。
優勢:
缺點:
目前仍是有不少種消息隊列的,各有特色。 對於選用RabbitMQ的理由,大概由於:延時低是它最大的特色,同時單機吞吐量也很不錯;也能進行分佈式集羣擴展;社區很是活躍。