最近在补充RabbitMQ的相关知识,
之前仅学习RabbitMQ的基础使用,集成到SpringBoot中,
只是使用了一些基础功能,如手动ACK、发布确认等,
对于队列的类型并没有深入研究,直接使用默认队列,
再次学习时才发现,RabbitMQ还有很多于我而言的高级功能,
先从Lazy队列开始补充,
分享如下,
这里不单单分享理论知识,同时,给出测试样例,验证lazy队列相关功能,加深理解。
官网地址:https://www.rabbitmq.com/lazy-queues.html
RabbitMQ从3.6.0版本开始,Broker引入了LazyQueues(惰性队列/延迟队列),该队列会即时将存入队列中的数据持久化到磁盘,当需要消费时才将数据加载到内存。
Lazy queues的主要目的之一是让队列支持长队列(百万级消息),实际应用中队列会变得很长的原因:
默认情况下,发送到RabbitMQ的消息会直接进入内存(外存内存),保证消费者可以快速获取消息,而持久化的消息进入内存的同时会写入到磁盘。
当Broker需要释放内存时,消息会从缓存交换到磁盘,将批量消息从内存交换到磁盘过程中耗时且阻塞队列(无法接收新消息)。虽然近期的RabbitMQ版本有改进交换算法,但是,对于数百万量级的消息交换仍不是很高效。
Lazy queues尝试将消息尽早落盘,换句话说,在内存中的数据会大大减少,但是,增加了磁盘的I/O。
RabbitMQ的队列可以配置为默认模式或lazy模式。
同时使用策略和队列参数指定队列模式时,队列参数优先级高于策略值,即Policy为Lazy,queue-mode参数为default,此时队列处于非lazy模式。
若在声明队列时通过可选参数配置队列模式,则只能通过删除队列并使用其他不同的参数重新声明来变更队列模式。
通过queue-mode配置队列为lazy模式,如下:
rabbitmqctl set_policy Lazy "^test-lazy-queue-1$" '{"queue-mode":"lazy"}' --vhost /tutorial --apply-to queues
rabbitmqctl set_policy Lazy "^test-lazy-queue-1$" "{""queue-mode"":""lazy""}" --vhost /tutorial --apply-to queues
命令参数解析如下表:
序号 | 参数 | 描述 |
---|---|---|
1 | rabbitmqctl | RabbitMQ客户端命令 |
2 | set_policy | 设定策略 |
3 | Lazy | Lazy标识 |
4 | ^test-lazy-queue-1$ | 队列名称,其中^和$可不填 |
5 | queue-mode | 队列模式,lazy或者default |
6 | –vhost | 指定vhost |
7 | –apply-to | 应用到某个对象,如queues,作用于队列 |
配置结果
通过RabbitMQ自带的监控平台,可以查看队列test-lazy-queue-1的工作模式为lazy,
如下图所示。其中Policy为Lazy(标识作用),queue-mode为lazy,即队列为lazy模式。
若队列是通过策略方式配置的工作模式,可以在运行时改变其工作模式,无需删除并重新声明队列。直接修改queue-mode为default即可变更队列模式。
rabbitmqctl set_policy Lazy "^test-lazy-queue-1$" '{"queue-mode":"default"}' --vhost /tutorial --apply-to queues
rabbitmqctl set_policy Lazy "^test-lazy-queue-1$" "{""queue-mode"":""default""}" --vhost /tutorial --apply-to queues
通过配置x-queue-mode参数可在声明队列时指定队列模式,如default和lazy。
不指定x-queue-mode,则默认为default,该模式在RabbitMQ3.60版本的Broker已经支持,截止目前没有革命性改进。
下面通过Java程序实现声明队里时指定x-queue-mode为lazy。
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.12.0version>
dependency>
创建队列test-lazy-queue-3时,通过x-queue-mode指定工作模式。
package com.monkey.java_study.mq.rabbitmq;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* RabbitMQ生产者.
*
* @author xindaqi
* @since 2022-07-27 15:50
*/
public class RabbitMQLazyProvider {
public static void main(String[] args) {
try (Connection connection = RabbitMQConnection.connectionFactoryDefault(); Channel channel = connection.createChannel()) {
String queueName = "test-lazy-queue-3";
boolean durableFlag = false;
boolean exclusiveFlag = false;
boolean autoDeleteFlag = false;
Map<String, Object> queueMode = new HashMap<>(2);
// 指定x-queue-mode为lazy
queueMode.put("x-queue-mode", "lazy");
// 声明队列
channel.queueDeclare(queueName, durableFlag, exclusiveFlag, autoDeleteFlag, queueMode);
String exchangeName = "test-exchange";
String routingKey = "test-routing-key";
// 指定exchange和DIRECT方式
channel.exchangeDeclare(exchangeName, Bui