文章目录
数据持久化的背景和挑战
持久化确保了即使 RabbitMQ 崩溃或重启,消息仍然不会丢失。同时,消息不会因为内存溢出而触发 paged out
操作,从而避免了性能下降。
但是,持久化也带来了一个问题:每条消息必须保存到内存和磁盘中,这导致了写入操作的延迟,从而降低了系统的整体并发能力。
引入惰性队列(Lazy Queue)
为了弥补这一性能损失,RabbitMQ 从 3.6 版本 引入了 惰性队列(Lazy Queue) 模式。惰性队列的目标是:
- 提升并发能力,同时确保消息不会丢失。
- 减少内存占用,避免内存满导致的阻塞。
惰性队列的特点
惰性队列有两个显著特点:
- 直接将消息写入磁盘,而不是先写入内存:
- 传统队列会首先将消息保存到内存中,然后根据是否需要持久化决定是否将其写入磁盘。
- 惰性队列则直接将消息写入磁盘,而不经过内存。这减少了内存压力和避免了因内存满导致的系统阻塞(如
page out
)。
- 磁盘写入优化:
- 惰性队列通过优化磁盘写入操作,提高了写入效率,比传统的持久化方式要高效得多。
惰性队列的潜在问题
尽管惰性队列解决了内存占用和阻塞问题,但也引入了新的挑战:
- 消费者读取延迟:消息被直接写入磁盘,消费者在读取时需要将消息从磁盘加载到内存,再投递给消费者。如果消费者的处理速度很快,但磁盘读取速度较慢,可能会影响消费者的处理速度。
为了解决这一问题,RabbitMQ 进行了进一步优化:
- 动态缓存机制:RabbitMQ 会根据消费者的处理速度动态调整消息的加载方式。
- 如果消费者处理消息的速度较慢,RabbitMQ 直接从磁盘加载消息。
- 如果消费者处理消息的速度较快,RabbitMQ 会提前将部分消息加载到内存中(最多 2048 条),避免磁盘读取的瓶颈影响消费者的处理速度。
RabbitMQ 中的惰性队列实现
- 从 RabbitMQ 3.12 版本 开始,所有队列默认都采用惰性队列模式,无法更改为传统队列模式。
- 在 3.8 版本 及以下的 RabbitMQ 中,若要使用惰性队列,需要手动配置。
如何创建惰性队列(Lazy Queue)
在 RabbitMQ 中,可以通过控制台、代码或注解来创建惰性队列。
在控制台中创建惰性队列:
- 创建一个队列时,勾选 Lazy Mode,系统会自动将参数
x-queue-mode=lazy
加入队列的arguments
中。
通过代码创建惰性队列:
- 使用
QueueBuilder
来声明队列时,调用lazy()
方法来启用惰性队列模式。例如:
@Bean
public Queue lazyQueue() {
return QueueBuilder
.durable("lazy.queue")
.lazy() // 开启Lazy模式
.build();
}
通过注解创建惰性队列:
- 使用
@Queue
注解时,添加arguments
参数来设置x-queue-mode=lazy
,从而声明惰性队列。例如:
@RabbitListener(queuesToDeclare = @Queue(
name = "lazy.queue",
dueable = "true",
arguments = @Argument(name = "x-queue-mode", value = "lazy")
))
public void listenLazyQueue(String msg) {
log.info("接收到 lazy.queue 的消息:{}", msg);
}
惰性队列的性能测试
- 在实际测试中,通过发送 100 万条消息 到惰性队列,可以看到处理的速度非常快,每秒处理 4 万到 5 万条消息,而且处理时间保持稳定,性能高于传统持久化队列。
- 相比传统队列,惰性队列避免了消息在内存中的存储,减少了内存压力,避免了内存满导致的
paged out
和阻塞问题。
惰性队列的优势
- 保证消息不丢失:即使 RabbitMQ 崩溃或重启,惰性队列依然能保证消息的持久性。
- 提升并发能力:由于不再需要将消息先存储到内存,写入磁盘的效率得到提升,从而增强了队列的处理能力。
- 避免内存阻塞:不会出现因为内存满导致的消息阻塞和系统停顿。
惰性队列的适用场景
- 适合高吞吐量且对延迟要求不高的场景。惰性队列通过减少内存的使用,并且优化磁盘写入,显著提升了消息队列的并发能力和稳定性,适用于大量消息处理的系统。
- 对于一些高并发的应用场景,使用惰性队列能够更好地处理负载,提高系统的响应能力。
小结
- 惰性队列(Lazy Queue)是 RabbitMQ 中为了解决持久化队列带来的性能问题而引入的新队列模式。
- 通过直接将消息写入磁盘、避免写入内存和内存溢出,惰性队列不仅保证了消息不丢失,还提升了并发处理能力。
- 在使用 RabbitMQ 时,如果对消息吞吐量和并发能力有较高要求,建议使用惰性队列模式。
关键点总结
- 惰性队列(Lazy Queue):直接将消息写入磁盘,避免内存占用,提高并发能力。
- 磁盘写入优化:相比传统持久化队列,惰性队列在写磁盘时更加高效,减少了
page out
阻塞问题。 - 消费者动态缓存:根据消费者处理速度调整内存缓存,优化读取性能。
- 使用方式:
- 控制台:勾选 Lazy Mode。
- 代码:使用
lazy()
方法。 - 注解:通过
arguments
配置x-queue-mode=lazy
。