RabbitMQ 惰性队列Lazy Queue

RabbitMQ 队列分为几种类型,按照不一样维度来分,能够分为排他性队列、普通队列、延迟队列、惰性队列、发布订阅队列等。redis

今天咱们讨论的主角是惰性队列 Lazy Queue。众所周知,队列能够存储消息并实现消息收发,这应该是消息队列中最重要的功能之一。算法

咱们使用消息队列有几个优点,解耦、高效、发完无论、高可用。上一篇咱们聊了RabbitMQ的镜像队列机制,镜像队列是高可用实现的一个有利保障,但在高可用的同时,必须提供高效的服务,才能被更多普通劳苦大众所接受。mongodb

RabbitMQ提供高效服务的几种途径,设置RAM节点、自动同步,先内存后磁盘的读取方式。在队列设置持久化后,咱们读取队列中的消息,若是都是先从内存后从磁盘读取,那么无形会占用更多系统资源,毕竟内存应该留给更多有须要的地方。缓存

若是发送端过快或消费端宕机,致使消息大量积压,此时消息仍是在内存和磁盘各存储一份,在消息大爆发的时候,MQ服务器会撑不住,影响其余队列的消息收发,能不能有效的处理这种状况呢。答案 惰性队列服务器

RabbitMQ从3.6.0版本开始引入了惰性队列(Lazy Queue)的概念。惰性队列会尽量的将消息存入磁盘中,而在消费者消费到相应的消息时才会被加载到内存中,它的一个重要的设计目标是可以支持更长的队列,即支持更多的消息存储。当消费者因为各类各样的缘由(好比消费者下线、宕机亦或者是因为维护而关闭等)而导致长时间内不能消费消息形成堆积时,惰性队列就颇有必要了并发

默认状况下,当生产者将消息发送到RabbitMQ的时候,队列中的消息会尽量的存储在内存之中,这样能够更加快速的将消息发送给消费者。即便是持久化的消息,在被写入磁盘的同时也会在内存中驻留一份备份。当RabbitMQ须要释放内存的时候,会将内存中的消息换页至磁盘中,这个操做会耗费较长的时间,也会阻塞队列的操做,进而没法接收新的消息。虽然RabbitMQ的开发者们一直在升级相关的算法,可是效果始终不太理想,尤为是在消息量特别大的时候app

惰性队列会将接收到的消息直接存入文件系统中,而不论是持久化的或者是非持久化的,这样能够减小了内存的消耗,可是会增长I/O的使用,若是消息是持久化的,那么这样的I/O操做不可避免,惰性队列和持久化消息可谓是“最佳拍档”。注意若是惰性队列中存储的是非持久化的消息,内存的使用率会一直很稳定,可是重启以后消息同样会丢失
 高并发

队列具有两种模式:default和lazy。默认的为default模式,在3.6.0以前的版本无需作任何变动。lazy模式即为惰性队列的模式,能够经过调用channel.queueDeclare方法的时候在参数中设置,也能够经过Policy的方式设置,若是一个队列同时使用这两种方式设置的话,那么Policy的方式具有更高的优先级。若是要经过声明的方式改变已有队列的模式的话,那么只能先删除队列,而后再从新声明一个新的
设置队列为惰性队列的命令:性能

rabbitmqctl set_policy Lazy "^myqueue$" '{"queue-mode":"lazy"}' --apply-to queues

惰性队列和普通队列相比,只有很小的内存开销。这里很难对每种状况给出一个具体的数值,可是咱们能够类比一下:当发送1千万条消息,每条消息的大小为1KB,而且此时没有任何的消费者,那么普通队列会消耗1.2GB的内存,而惰性队列只消耗1.5MB的内存测试

据官网测试数据显示,对于普通队列,若是要发送1千万条消息,须要耗费801秒,平均发送速度约为13000条/秒。若是使用惰性队列,那么发送一样多的消息时,耗时是421秒,平均发送速度约为24000条/秒。出现性能误差的缘由是普通队列会因为内存不足而不得不将消息换页至磁盘。若是有消费者消费时,惰性队列会耗费将近40MB的空间来发送消息,对于一个消费者的状况,平均的消费速度约为14000条/秒。

若是要将普通队列转变为惰性队列,那么咱们须要忍受一样的性能损耗。当转变为惰性队列的时候,首先须要将缓存中的消息换页至磁盘中,而后才能接收新的消息。反之,当将一个惰性队列转变为普通队列的时候,和恢复一个队列执行一样的操做,会将磁盘中的消息批量的导入到内存中。
 

队列参数的设置

 

 

  • Message TTL(x-message-ttl):设置队列中的全部消息的生存周期(统一为整个队列的全部消息设置生命周期), 也能够在发布消息的时候单独为某个消息指定剩余生存时间,单位毫秒, 相似于redis中的ttl,生存时间到了,消息会被从队里中删除,注意是消息被删除,而不是队列被删除, 特性Features=TTL, 单独为某条消息设置过时时间AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties().builder().expiration(“6000”); 

  • Auto Expire(x-expires): 当队列在指定的时间没有被访问(consume, basicGet, queueDeclare…)就会被删除,Features=Exp

  • Max Length(x-max-length): 限定队列的消息的最大值长度,超过指定长度将会把最先的几条删除掉, 相似于mongodb中的固定集合,例如保存最新的100条消息, Feature=Lim

  • Max Length Bytes(x-max-length-bytes): 限定队列最大占用的空间大小, 通常受限于内存、磁盘的大小, Features=Lim B

  • Dead letter exchange(x-dead-letter-exchange): 当队列消息长度大于最大长度、或者过时的等,将从队列中删除的消息推送到指定的交换机中去而不是丢弃掉,Features=DLX

  • Dead letter routing key(x-dead-letter-routing-key):将删除的消息推送到指定交换机的指定路由键的队列中去, Feature=DLK

  • Maximum priority(x-max-priority):优先级队列,声明队列时先定义最大优先级值(定义最大值通常不要太大),在发布消息的时候指定该消息的优先级, 优先级更高(数值更大的)的消息先被消费,

  • Lazy mode(x-queue-mode=lazy): Lazy Queues: 先将消息保存到磁盘上,不放在内存中,当消费者开始消费的时候才加载到内存中

  • Master locator(x-queue-master-locator)

总结:

惰性队列的存在是为了减小内存占用,避免因为内存不足而产生的换页操做。

但对比惰性队列和普通队列,若是在内存和磁盘均不设限制的话,采用普通队列的效率会更高,毕竟磁盘再快,对比内存也会差一个数量级。

但若是服务器的配置捉襟见肘的话,能够考虑惰性队列的存在,毕竟惰性队列相比普通队列,性能差别并不大,在极端状况下还会更好,您以为呢?

 

使用lazy queue会有如下几种搭配

 

lazy queue 消息不持久化 , 可是这种模式仍是会把消息放到硬盘里,RAM的使用率会一直很稳定,可是重启后同样会丢失消息

lazy queue 消息持久化,这种方式无疑是最佳搭配,消息放到硬盘而且不会由于服务器重启而丢失,面对高并发也是从容不已。 面包和咖啡更配哦

相关文章
相关标签/搜索