延迟消息: 生产者放松消息时指定一个时间,消费者不会立刻受到消息,而是在指定时间之后才收到消息。
延迟任务: 设置在一定时间之后才执行的任务.
死信交换机
我么可以通过死信交换机实现延迟消息。
当一个队列的消息满足下列情况之一时,就会成为死信(dead letter):
- 消费者使用 basic.reject 或 basic.nack 声明消费失败,并且消息的 requeue 参数设置为 false
- 消息是一个过期消息(达到了队列或消息本身设置的过期时间),超时无人消费
- 要投递的队列消息堆积满了,最早的消息可能成为死信
如果队列通过 dead-letter-exchange 属性指定了一个交换机,那么该队列中的死信就会投递到这个交换机中。这个交换机成为死信交换机(Dead Letter Exchange, 简称 DLX)。
下图给 simple.queue 队列绑定了一个死信交换机
下图我定义了两个队列和两个交换机,simple.direct 绑定 simple.queue(指定了死信交换机,见上图), dix.direct 绑定了dix.queue,我们再给dix.queue绑定一个消费者。不要让 simple.queue 绑定消费者,不然无法测试出死信。
@RabbitListener(queues = "dix.queue")
public void onMessage(String message) {
log.info("receive message: {}", message);
}
发送消息的代码
@Test
public void testSendTTLMessage(){
Message message = MessageBuilder
.withBody("hello".getBytes(StandardCharsets.UTF_8))
.setExpiration("3000")//设置过期时间 单位 ms
.build();
rabbitTemplate.convertAndSend("simple.direct","hi",message);
log.info("消息发送成功");
}
延迟消息插件
RabbitMQ 的官方也推出了一个插件,原生支持延迟消息功能。该插件的原理是设计了一种支持延迟消息功能的交换机,当消息投递到交换机可以暂存一定时间,到期后再投递到队列。
官方文档:
Scheduling Messages with RabbitMQ | RabbitMQ
1.下载插件
插件下载地址:
Releases · rabbitmq/rabbitmq-delayed-message-exchange (github.com)
下载对应版本的插件:
然后复制到RabbitMQ的plugins目录中。使用命令启用插件:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
docker 命令:
docker exec -it 容器名/容器id rabbitmq-plugins enable rabbitmq_delayed_message_exchange
基于注解方式
在consumer服务基于@RabbitListener注解来声明队列、交换机和绑定队列和交换机,并且设置交换机为延迟交换机:
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "delay.queue", durable = "true"),
exchange = @Exchange(value = "delay.direct", delayed = "true"),
key = "delay"
))
public void listenDelayQueue(String msg) {
log.info("delay.queue:" + msg);
}
| delayed = "true" | 设置交换机为延迟交换机 |
基于@Bean方式
在consumer服务基于@Bean注解来声明交换机、队列和绑定队列和交换机,并且设置交换机为延迟交换机:
@Configuration
public class DirectConfiguration {
@Bean
public DirectExchange delayExchange() {
return ExchangeBuilder
.directExchange("delay.direct")
.delayed() // 设置为延迟交换机
.durable(true)
.build();
}
@Bean
public Queue delayedQueue() {
return new Queue("delay.queue");
}
@Bean
public Binding delayQueueBinding() {
return BindingBuilder.bind(delayedQueue()).to(delayExchange()).with("delay");
}
}
| .delayed() | 设置交换机为延迟交换机 |
延迟消息发送
在publisher服务中的测试类添加一个测试方法,通过消息头x-delay来设置过期时间,实现延迟消息发送:
@Test
void testSendDelayMessage() {
rabbitTemplate.convertAndSend("delay.direct", "delay", "hello", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setDelay(10000);
return message;
}
});
log.info("消息发送成功");
}
| .setDelay() | 通过消息头x-delay来设置消息的延迟时间 |