RabbitMQ 生产者可靠性——生产者确认

原理:

生产者确认更加注重 消息发送失败时该怎么办

消息发送失败 采用的是确认机制(有两种确认机制:Publisher Confirm 和 Publisher Return)

 交换机找不到生产者传递过来的那个RoutingKey的队列,交换机就会路由失败,也就是上面第一种情况

交换机路由失败情况就是自己代码写错了导致的,检查代码就行了

 

代码实现:

 

交换机路由失败时,RabbitMQ会用Publisher Confirm机制返回ACK,告诉生产者 消息投递成功(生产者通过 ConfirmCallback 回调方法就可以接收到了),还会用Publisher Return机制告诉生产者路由异常原因(生产者通过 ReturnCallback 回调方法就可以接收到了)

除了第一种交换机路由失败情况,其他情况下,RabbitMQ会用Publisher Confirm机制返回ACK或者NACK,告诉生产者 消息投递成功或者失败(生产者通过 ConfirmCallback 回调方法就可以接收到了)

 

编写回调:

ReturnCallback

编写回调:

ConfirmCallback 是在每一个消息发送时单独指定

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

代码示例:

1. 编写配置

spring:
rabbitmq:
host: 192.168.88.130
port: 5672
virtual-host: /hmall
username: hmall
password: 123
listener:
simple:
prefetch: 1
connection-timeout: 1s #设置MQ的连接超时时间
template:
retry:
enabled: true #开启超时重试机制
initial-interval: 1000ms #失败后的初始等待时间
multiplier: 1 #失败后下次的等待时长倍数,下次等待时长 = initial - interval * multiplier
max-attempts: 3 #最大重试次数
publisher-confirm-type: correlated
publisher-returns: true

2. Publisher Return 的回调:

package com.itheima.config_RabbitMQ;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
public class MqConfirmConfig implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
//配置回调
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
log.debug("收到消息的return callback,exchange:{}, key:{}, msg:{}, code:{}, text:{}",
returnedMessage.getExchange(), returnedMessage.getRoutingKey(), returnedMessage.getMessage(),
returnedMessage.getReplyCode(), returnedMessage.getReplyText());
}
});
}
}

3. ConfirmCallback回调

@GetMapping("/mq06")
public void testPublisherConfirm() throws Exception {
//创建cd
CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());//参数:uuid
//添加ConfirmCallback
cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) { //onFailure是指Spring内部在处理的时候失败了,既不是ack也不是nack,跟RabbitMQ无关
log.error("消息回调失败", ex);
}

@Override
public void onSuccess(CorrelationData.Confirm result) {//进入onSuccess方法是指RabbitMQ的回调成功了,即生产者收到了MQ的回执
log.debug("收到confirm callback回执");
if(result.isAck())
log.debug("消息发送成功,收到ack");
else
log.error("消息发送失败,收到nack,原因是:" + result.getReason());
}
});
rabbitTemplate.convertAndSend("hmall.direct", "red", "hello", cd);//四个参数:交换机名称、RoutingKey、要发送的消息、cd
Thread.sleep(2000);
}

posted @ 2023-12-03 17:44  1stzz1  阅读(135)  评论(0)    收藏  举报