RabbitMQ之惰性队列(Lazy Queue)
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/mq/rabbitmq-analysis-of-lazy-queue/
RabbitMQ從3.6.0版本開(kāi)始引入了惰性隊(duì)列(Lazy Queue)的概念。惰性隊(duì)列會(huì)盡可能的將消息存入磁盤(pán)中,而在消費(fèi)者消費(fèi)到相應(yīng)的消息時(shí)才會(huì)被加載到內(nèi)存中,它的一個(gè)重要的設(shè)計(jì)目標(biāo)是能夠支持更長(zhǎng)的隊(duì)列,即支持更多的消息存儲(chǔ)。當(dāng)消費(fèi)者由于各種各樣的原因(比如消費(fèi)者下線、宕機(jī)亦或者是由于維護(hù)而關(guān)閉等)而致使長(zhǎng)時(shí)間內(nèi)不能消費(fèi)消息造成堆積時(shí),惰性隊(duì)列就很有必要了。
默認(rèn)情況下,當(dāng)生產(chǎn)者將消息發(fā)送到RabbitMQ的時(shí)候,隊(duì)列中的消息會(huì)盡可能的存儲(chǔ)在內(nèi)存之中,這樣可以更加快速的將消息發(fā)送給消費(fèi)者。即使是持久化的消息,在被寫(xiě)入磁盤(pán)的同時(shí)也會(huì)在內(nèi)存中駐留一份備份。當(dāng)RabbitMQ需要釋放內(nèi)存的時(shí)候,會(huì)將內(nèi)存中的消息換頁(yè)至磁盤(pán)中,這個(gè)操作會(huì)耗費(fèi)較長(zhǎng)的時(shí)間,也會(huì)阻塞隊(duì)列的操作,進(jìn)而無(wú)法接收新的消息。雖然RabbitMQ的開(kāi)發(fā)者們一直在升級(jí)相關(guān)的算法,但是效果始終不太理想,尤其是在消息量特別大的時(shí)候。
惰性隊(duì)列會(huì)將接收到的消息直接存入文件系統(tǒng)中,而不管是持久化的或者是非持久化的,這樣可以減少了內(nèi)存的消耗,但是會(huì)增加I/O的使用,如果消息是持久化的,那么這樣的I/O操作不可避免,惰性隊(duì)列和持久化消息可謂是“最佳拍檔”。注意如果惰性隊(duì)列中存儲(chǔ)的是非持久化的消息,內(nèi)存的使用率會(huì)一直很穩(wěn)定,但是重啟之后消息一樣會(huì)丟失。
隊(duì)列具備兩種模式:default和lazy。默認(rèn)的為default模式,在3.6.0之前的版本無(wú)需做任何變更。lazy模式即為惰性隊(duì)列的模式,可以通過(guò)調(diào)用channel.queueDeclare方法的時(shí)候在參數(shù)中設(shè)置,也可以通過(guò)Policy的方式設(shè)置,如果一個(gè)隊(duì)列同時(shí)使用這兩種方式設(shè)置的話,那么Policy的方式具備更高的優(yōu)先級(jí)。如果要通過(guò)聲明的方式改變已有隊(duì)列的模式的話,那么只能先刪除隊(duì)列,然后再重新聲明一個(gè)新的。
在隊(duì)列聲明的時(shí)候可以通過(guò)“x-queue-mode”參數(shù)來(lái)設(shè)置隊(duì)列的模式,取值為“default”和“l(fā)azy”。下面示例中演示了一個(gè)惰性隊(duì)列的聲明細(xì)節(jié):
Map<String, Object> args = new HashMap<String, Object>(); args.put("x-queue-mode", "lazy"); channel.queueDeclare("myqueue", false, false, false, args);對(duì)應(yīng)的Policy設(shè)置方式為:
rabbitmqctl set_policy Lazy "^myqueue$" '{"queue-mode":"lazy"}' --apply-to queues惰性隊(duì)列和普通隊(duì)列相比,只有很小的內(nèi)存開(kāi)銷。這里很難對(duì)每種情況給出一個(gè)具體的數(shù)值,但是我們可以類比一下:當(dāng)發(fā)送1千萬(wàn)條消息,每條消息的大小為1KB,并且此時(shí)沒(méi)有任何的消費(fèi)者,那么普通隊(duì)列會(huì)消耗1.2GB的內(nèi)存,而惰性隊(duì)列只消耗1.5MB的內(nèi)存。
據(jù)官網(wǎng)測(cè)試數(shù)據(jù)顯示,對(duì)于普通隊(duì)列,如果要發(fā)送1千萬(wàn)條消息,需要耗費(fèi)801秒,平均發(fā)送速度約為13000條/秒。如果使用惰性隊(duì)列,那么發(fā)送同樣多的消息時(shí),耗時(shí)是421秒,平均發(fā)送速度約為24000條/秒。出現(xiàn)性能偏差的原因是普通隊(duì)列會(huì)由于內(nèi)存不足而不得不將消息換頁(yè)至磁盤(pán)。如果有消費(fèi)者消費(fèi)時(shí),惰性隊(duì)列會(huì)耗費(fèi)將近40MB的空間來(lái)發(fā)送消息,對(duì)于一個(gè)消費(fèi)者的情況,平均的消費(fèi)速度約為14000條/秒。
如果要將普通隊(duì)列轉(zhuǎn)變?yōu)槎栊躁?duì)列,那么我們需要忍受同樣的性能損耗。當(dāng)轉(zhuǎn)變?yōu)槎栊躁?duì)列的時(shí)候,首先需要將緩存中的消息換頁(yè)至磁盤(pán)中,然后才能接收新的消息。反之,當(dāng)將一個(gè)惰性隊(duì)列轉(zhuǎn)變?yōu)槠胀?duì)列的時(shí)候,和恢復(fù)一個(gè)隊(duì)列執(zhí)行同樣的操作,會(huì)將磁盤(pán)中的消息批量的導(dǎo)入到內(nèi)存中。
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/mq/rabbitmq-analysis-of-lazy-queue/
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
總結(jié)
以上是生活随笔為你收集整理的RabbitMQ之惰性队列(Lazy Queue)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RabbitMQ之监控(3)
- 下一篇: RabbitMQ管理(1)——多租户与权