目录
[3.1. 惰性队列与传统持久化的主要区别:](#3.1. 惰性队列与传统持久化的主要区别:)
一、引言
我们在使用MQ的过程中,除了生产者发送消息/连接MQ时存在的可靠性之外,MQ自身在收发消息时也存在着消息可靠性问题。如果对MQ的使用场景和机制不了解,就可能造成消息丢失等严重的问题。
在RabbitMQ中,消息的存储和处理方式可以根据不同的需求进行配置。主要有三种消息存储机制:非持久化消息、持久化消息和惰性队列。在非持久化的情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟,提升吞吐性能。
但是将消息直接存储在内存这样会导致两个问题:
一旦MQ宕机,内存中的消息会丢失。
内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞。
如上图所示,设置消息非持久化时,当大量消息请求来时,保存到内存的过程中,大量消息消费不及时会占满内存,这时MQ会将消息转移到磁盘(即Paged Out),此时大量消息处于阻塞状态。
因此,这就涉及到我们对消息进行持久化操作的问题。RabbitMQ实现数据持久化包括3个方面:
- 交换机持久化
- 队列持久化
- 消息持久化
RabbitMQ为我们提供了两种持久化的方案,持久化消息和惰性队列。 下面我们就来分析讲解下两种方案的使用场景、使用方式及区别**。**
二、RabbitMQ传统持久化消息
在3.12版本前,rabbitmq一直使用传统方法作为持久化,就是将使用者创建的交换机、队列和消息时,将durable设置为true。以下是该属性在RabbitMQ的浏览器界面的队列是否持久化的配置选项
我们在使用Spring AMQP时,Spring已经为我们提供了默认的解决方案,在API中给我们将交换机、队列和消息配置持久化了,实现内存和磁盘双重存储。这保证了即使RabbitMQ服务器重启或崩溃,消息也不会丢失。这种机制虽然增加了一些处理延迟,但大大提高了消息的可靠性。
适用场景:需要确保消息不丢失的关键业务场景,如订单处理、交易信息等。
Spring源码中对消息队列默认设置为持久化,即durable = true
Spring源码中对交换机默认设置为持久化,即durable = true
Spring源码中对消息默认设置为持久化,即durable = true
队列设为持久化后的效果,我们通过黄线可以看到消息队列在每秒处理消息的速率和稳定性上都比较高,已经没有Paged Out消息积压的情况:
三、惰性队列
从RabbitMQ的3.6.0版本起,增加了Lazy Queue的概念即惰性队列,声明队列时需要指定x-queue-mode属性为lazy。 惰性队列特征如下:
接收到消息后直接存入磁盘,不再存储到内存
消费者要消费消息时才会从磁盘中读取并加载到内存(可以提前缓存部分消息到内存,最多2048条)
注:在3.12版本后,所有队列都是Lazy Queue模式,不需要指定属性,且无法更改。以下是3.6.0到3.12之间的RabbitMQ的版本设置惰性队列的方式:
通过RabbitMQ浏览器界面:
通过代码形式:
适用场景:Lazy queue 适用于消息量较大、消息消费速度较慢的场景。它可以处理大量的消息,而不会对内存造成过大的压力。传统的持久化方法适用于消息量较小、消息消费速度较快的场景,可以提供更低的延迟。
3.1. 惰性队列与传统持久化的主要区别:
数据存储位置:传统的持久化方法将消息和队列的数据存储在磁盘上,而 lazy queue 将消息存储在磁盘上,但队列的元数据仍存储在内存中。这意味着 lazy queue 在存储大量消息时可以减轻内存压力,而传统持久化方法需要将所有数据都存储在磁盘上。
内存使用:传统的持久化方法需要将所有消息和队列的元数据都加载到内存中,这可能会导致内存消耗过大。而 lazy queue 只需要加载当前需要处理的消息到内存中,减少了内存的使用量。
性能优化:Lazy queue 在设计上采用了一些性能优化策略。例如,它使用预取(prefetch)策略,只在需要时将一批消息加载到内存中,减少了磁盘读取的次数。此外,RabbitMQ 还采用了一些磁盘读写优化技术,如顺序写入和批量写入,以提高性能。