1.什么是延迟队列?怎么实现的?
延迟队列指的是存储对应的延迟消息,消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
RabbitMQ 本身是没有延迟队列的,要实现延迟消息,一般有两种方式:
1.使用 RabbitMQ 的死信交换机(Exchange)和消息的存活时间 TTL(消息存活时间)。生产者将消息发送到一个特定的交换器,该交换器将这些消息路由到一个具有TTL属性的队列。当消息在队列中的时间超过设定的TTL值时,消息会被发送到死信队列。消费者可以从死信队列中获取这些消息并进行相应的处理。
2.可以使用 rabbitmq_delayed_message_exchange
插件:这个插件允许交换器直接支持延迟消息的发布。使用此插件,生产者可以在发送消息时指定一个延迟时间,然后交换器会在该时间过后才将消息路由到相应的队列中。这样一来,消费者只能在延迟时间过后才能接收到消息。
2.在 RabbitMQ 中实现订单超时取消功能,可以通过结合使用延迟队列和死信队列来完成。以下是一个实现步骤:
-
创建订单队列和死信队列:
- 创建一个订单队列(
orderQueue
)用于接收订单请求。 - 创建一个死信队列(
deadLetterQueue
)用于处理超时取消的订单。
- 创建一个订单队列(
-
设置延迟队列:
- 创建一个延迟队列(
delayQueue
)用于处理订单超时逻辑。此队列会设置一个消息过期时间(TTL),在时间到达后,消息会被发送到死信队列。
- 创建一个延迟队列(
-
配置队列与交换机:
- 设置延迟队列的 TTL,配置消息的过期时间,并将延迟队列的
x-dead-letter-exchange
属性设置为死信交换机,x-dead-letter-routing-key
设置为死信队列的路由键。 - 配置死信队列的交换机,确保超时的订单消息能够被正确路由到死信队列。
- 设置延迟队列的 TTL,配置消息的过期时间,并将延迟队列的
-
实现逻辑:
- 生产者在订单生成后生成一条带有TTL(例如 15分钟)的延迟取消订单消息。
- 该消息被发送到延迟队列交换机,并通过绑定的路由键投递到延迟队列。
- 在延迟队列中,消息的TTL到期后,消息会被发送到死信队列交换机。
- 死信队列交换机将消息投递到死信队列。
- 消费者监听死信队列的消息,一旦有消息,消费者会立即消费并执行超时取消的业务逻辑,例如更新订单状态和发送通知。
示例代码
以下是 RabbitMQ 的示例配置和代码片段:
1. 创建延迟队列和死信队列的配置:
# 延迟队列的配置
rabbitmq:
exchanges:
delayExchange:
type: direct
durable: true
queues:
delayQueue:
durable: true
arguments:
x-dead-letter-exchange: "deadLetterExchange"
x-dead-letter-routing-key: "cancelOrder"
x-message-ttl: 900000 # 消息过期时间,单位是毫秒 (15分钟)
deadLetterQueue:
durable: true
bindings:
delayQueue:
exchange: delayExchange
routing-key: order
deadLetterQueue:
exchange: deadLetterExchange
routing-key: cancelOrder
2. 发送订单消息到延迟队列:
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {
// 声明交换机和队列
channel.exchangeDeclare("delayExchange", "direct", true);
channel.queueDeclare("delayQueue", true, false, false, null);
channel.queueBind("delayQueue", "delayExchange", "order");
channel.exchangeDeclare("deadLetterExchange", "direct", true);
channel.queueDeclare("deadLetterQueue", true, false, false, null);
channel.queueBind("deadLetterQueue", "deadLetterExchange", "cancelOrder");
// 发送消息到延迟队列
String message = "Order data";
channel.basicPublish("delayExchange", "order", null, message.getBytes());
}
3. 处理死信队列中的超时订单:
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {
channel.exchangeDeclare("deadLetterExchange", "direct", true);
channel.queueDeclare("deadLetterQueue", true, false, false, null);
channel.queueBind("deadLetterQueue", "deadLetterExchange", "cancelOrder");
// 消费死信队列中的消息
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println("Received canceled order: " + message);
// 执行超时取消逻辑,例如更新订单状态
};
channel.basicConsume("deadLetterQueue", true, deliverCallback, consumerTag -> { });
}
这样,当订单在延迟队列中超时后,它们会被转发到死信队列,并通过消费者处理超时取消逻辑。