死信消息
出现死信消息的原因
- 出现异常的时候通过
reject
或者nack
的并且不重入队列则会进入死信队列 - 设置队列
x-message-ttl
属性或者消息的属性中设置了setExpiration
时间(谁小谁先生效) - 消息长度超过了队列的最大长度,通过设置队列的
x-max-length
来设置队列的最大长度
死信消息配置
- 首先需要创建一个死信队列和死信交换机并且绑定(基于SpringBoot的方式)
@Bean
public Exchange dlxExchange() {
return new TopicExchange("dlx.exchange");
}
@Bean
public Queue dlxQueue() {
return new Queue("dlx.queue");
}
@Bean
public Binding dlxBinding() {
return new Binding(this.dlxQueue().getName(),
Binding.DestinationType.QUEUE,
this.dlxExchange().getName(),
"#",
null);
}
- 其次在业务消息队列中指定属性
x-dead-letter-exchange
,交换机的名称是上面声明的交换机名称
@Bean
public Queue queue() {
Map<String, Object> paramMap = Maps.newHashMap();
paramMap.put("x-dead-letter-exchange", "dlx.exchange");
return new Queue("queue.test", true, false, false, paramMap);
}
死信队列中的消息处理
- 对于死信队列中的消息可以通过消息监听器监听,对不同的业务根据配置的规则可以进行重新处理或者进行业务告警
延时消息
业务场景
- 针对处理失败的业务场景可以通过进入延时队列增加业务处理容错性
- 有些业务比如订单可能需要支付的过程,超过时间没有支付需要取消订单
延时消息配置
插件安装
- 查看是否安装了插件
rabbitmq-plugins list
看是否存在启用插件,如下所示表示启用了插件,否则可以进行下面的步骤
[E*] rabbitmq_delayed_message_exchange 3.8.0
- docker安装
- 下载插件3.8版本
- 执行命令
docker cp rabbitmq_delayed_message_exchange-3.8.0.ez rabbitmq:/
- 进入容器
docker exec -it rabbitmq bash
- 复制到plugins目录
cp /rabbitmq_delayed_message_exchange-3.8.0.ez plugins/
,这里的plugins目录需要根据自己的容器来确定,这里的目录是/opt/rabbitmq。可以通过命令whereis rabbitmq
或者echo $PATH
来查找rabbitmq的目录 - 启用插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
- 非docker安装则少了docker复制的那一步,其它的步骤一样
交换机队列配置
@Bean
public Queue delayQueue() {
return new Queue("delay.queue");
}
@Bean
public CustomExchange delayExchange(Queue delayQueue) {
Map<String, Object> param = new HashMap<>(1);
param.put("x-delayed-type", "direct");
return new CustomExchange("delay.exchange",
"x-delayed-message",
true,
false,
param);
}
@Bean
Binding delayMessageBinding(Queue delayQueue,CustomExchange delayExchange){
return BindingBuilder
.bind(delayQueue)
.to(delayExchange)
.with("delay.route")
.noargs();
}
消息发送
- 消息发送的时候需要指定消息发送的延迟时长,这样消息会在指定的时间后发送给队列进行消费
rabbitTemplate.convertAndSend("delay.exchange",
"delay.route",
orderVo,
postProcessor -> {
postProcessor.getMessageProperties().setDelay(5000);
return postProcessor; },
new CorrelationData(orderVo.getId().toString()));