延迟交换机
作用
首先,之前的消息过期时间是通过给消息或者队列加消息过期时间实现,会存在两个问题:
我们需要根据不同的业务在队列上指定不同的过期策略,这时队列的名称也不能相同,如果业务场景复杂时,维护成本过高。
因为队列先进先出的原则且串行消费,如果先进入队列的消息过期时间较长,后进入队列的过期时间较短,那么在该场景下,待先进入的消息被消费完成后后面的消息早已过期,导致本来应该很快被消费的消息等待处理的时间过长。
安装插件
在github上下载对应版本的插件并上传到rabbitmq服务器中
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/tag/3.9.0
复制插件到容器的plugins目录下
docker cp rabbitmq_delayed_message_exchange-3.9.0.ez rabbitmq:/opt/rabbitmq/plugins
进入到容器内部可以看到该插件
docker exec -it rabbitmq bash
cd opt/rabbitmq/plugins
ls
进入的sbin目录中启动该插件
cd ../sbin/
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
然后退出容器,并重启rabbitmq容器
exit
docker restart rabbitmq
在客户端的构建交换机这里我们就可以看到多了一个x-delayed-message类型
使用API
延迟交换机的相关配置信息
@Configuration
public class DelayedConfig {
public static final String DELAYED_EXCHANGE = "delayed-exchange";
public static final String DELAYED_QUEUE = "delayed-queue";
public static final String DELAYED_ROUTING_KEY = "delayed.#";
@Bean
public Exchange delayedExchange(){
Map<String, Object> arguments = new HashMap<>();
//指定通信方式为topic
arguments.put("x-delayed-type","topic");
//使用CustomExchange类创建,类型要指定为“x-delayed-message”类型
Exchange exchange = new CustomExchange(DELAYED_EXCHANGE,"x-delayed-message",true,false,arguments);
return exchange;
}
@Bean
public Queue delayedQueue(){
return QueueBuilder.durable(DELAYED_QUEUE).build();
}
@Bean
public Binding delayedBinding(Queue delayedQueue,Exchange delayedExchange){
return BindingBuilder.bind(delayedQueue).to(delayedExchange).with(DELAYED_ROUTING_KEY).noargs();
}
}
生产者
@SpringBootTest
public class DelayedPublisherTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publish(){
rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "delayed.abc", "xxxx", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//设置消息延迟发送的时间
message.getMessageProperties().setDelay(10000);
return message;
}
});
}
}
通过上述代码说明消息会在发送出去后被路由到一个特定的延迟交换机上,并在该交换机中等待指定的延迟时间。在延迟时间到达后,消息将被转发到指定的目标队列中,供消费者进行消费。
但是通过此插件实现延迟消息也会有弊端:
插件的版本一定要和RabbitMQ的版本相对应,可以看一下插件每个版本的兼容性说明,开启插件后一定重启RabbitMQ服务。
消息的可靠性问题,在极端情况下(如 RabbitMQ 节点故障或网络异常等),可能会造成消息没有正常发送或丢失的情况。