rabbitmq從3.6.0版本開始引入了惰性佇列(lazy queue)的概念。惰性佇列會盡可能的將訊息存入磁碟中,而在消費者消費到相應的訊息時才會被載入到記憶體中,它的乙個重要的設計目標是能夠支援更長的佇列,即支援更多的訊息儲存。當消費者由於各種各樣的原因(比如消費者下線、宕機亦或者是由於維護而關閉等)而致使長時間內不能消費訊息造成堆積時,惰性佇列就很有必要了。
預設情況下,當生產者將訊息傳送到rabbitmq的時候,佇列中的訊息會盡可能的儲存在記憶體之中,這樣可以更加快速的將訊息傳送給消費者。即使是持久化的訊息,在被寫入磁碟的同時也會在記憶體中駐留乙份備份。當rabbitmq需要釋放記憶體的時候,會將記憶體中的訊息換頁至磁碟中,這個操作會耗費較長的時間,也會阻塞佇列的操作,進而無法接收新的訊息。雖然rabbitmq的開發者們一直在公升級相關的演算法,但是效果始終不太理想,尤其是在訊息量特別大的時候。
惰性佇列會將接收到的訊息直接存入檔案系統中,而不管是持久化的或者是非持久化的,這樣可以減少了記憶體的消耗,但是會增加i/o的使用,如果訊息是持久化的,那麼這樣的i/o操作不可避免,惰性佇列和持久化訊息可謂是「最佳拍檔」。注意如果惰性佇列中儲存的是非持久化的訊息,記憶體的使用率會一直很穩定,但是重啟之後訊息一樣會丟失。
佇列具備兩種模式:default和lazy。預設的為default模式,在3.6.0之前的版本無需做任何變更。lazy模式即為惰性佇列的模式,可以通過呼叫channel.queuedeclare方法的時候在引數中設定,也可以通過policy的方式設定,如果乙個佇列同時使用這兩種方式設定的話,那麼policy的方式具備更高的優先順序。如果要通過宣告的方式改變已有佇列的模式的話,那麼只能先刪除佇列,然後再重新宣告乙個新的。
在佇列宣告的時候可以通過「x-queue-mode」引數來設定佇列的模式,取值為「default」和「lazy」。下面示例中演示了乙個惰性佇列的宣告細節:
map args = new hashmap();
args.put("x-queue-mode", "lazy");
channel.queuedeclare("myqueue", false, false, false, args);
對應的policy設定方式為:
惰性佇列和普通佇列相比,只有很小的記憶體開銷。這裡很難對每種情況給出乙個具體的數值,但是我們可以模擬一下:當傳送1千萬條訊息,每條訊息的大小為1kb,並且此時沒有任何的消費者,那麼普通佇列會消耗1.2gb的記憶體,而惰性佇列只消耗1.5mb的記憶體。
據官網測試資料顯示,對於普通佇列,如果要傳送1千萬條訊息,需要耗費801秒,平均傳送速度約為13000條/秒。如果使用惰性佇列,那麼傳送同樣多的訊息時,耗時是421秒,平均傳送速度約為24000條/秒。出現效能偏差的原因是普通佇列會由於記憶體不足而不得不將訊息換頁至磁碟。如果有消費者消費時,惰性佇列會耗費將近40mb的空間來傳送訊息,對於乙個消費者的情況,平均的消費速度約為14000條/秒。
如果要將普通佇列轉變為惰性佇列,那麼我們需要忍受同樣的效能損耗。當轉變為惰性佇列的時候,首先需要將快取中的訊息換頁至磁碟中,然後才能接收新的訊息。反之,當將乙個惰性佇列轉變為普通佇列的時候,和恢復乙個佇列執行同樣的操作,會將磁碟中的訊息批量的匯入到記憶體中。
RabbitMQ惰性佇列
惰性佇列會盡可能的將訊息存入磁碟中,而在消費者消費到相應的訊息時才會被載入到記憶體中,它的乙個重要的設計目標是能夠支援更長的佇列,即支援更多的訊息儲存。當消費者由於各種各樣的原因 比如消費者下線 宕機亦或者是由於維護而關閉等 而致使長時間內不能消費訊息造成堆積時,惰性佇列就很有必要了。預設情況下,當...
RabbitMQ 惰性佇列Lazy Queue
rabbitmq 佇列分為幾種型別,按照不同維度來分,可以分為排他性佇列 普通佇列 延遲佇列 惰性佇列 發布訂閱佇列等。今天我們討論的主角是惰性佇列 lazy queue。眾所周知,佇列可以儲存訊息並實現訊息收發,這應該是訊息佇列中最重要的功能之一。rabbitmq提供高效服務的幾種途徑,設定ram...
RabbitMQ之(延遲佇列)
什麼是延時佇列,延時佇列應用於什麼場景 延時佇列顧名思義,即放置在該佇列裡面的訊息是不需要立即消費的,而是等待一段時間之後取出消費。那麼,為什麼需要延遲消費呢?我們來看以下的場景 rabbitmq的queue可以配置x dead letter exchange和x dead letter routi...