RabbitMQ学习六 生产者可靠性
spring:
rabbitmq:
addresses: xxx.xx.xx.xx
port: 5672
username: xxxxx
password: xxxx
virtual-host: /xxxx
connection-timeout: 1s #设置MQ的连接超时时间
template:
retry:
max-attempts: 3 #最大重试次数
enabled: true #开启重试机制
multiplier: 1 #失败后下次等待时长倍数,下次等待时长=initial-interval * multiplier
initial-interval: 1000ms # 失败后的初始等待时间
注意上述重试配置是写在template配置里面。 配置上述重试之后,把MQ服务停掉
停掉mq之后,向mq发送一个消息
注意:
如果对于业务性能有要求,建议 禁用 重试机制。如果一定要使用,请合理分配等待时长和重试次数
Publisher Confirm和 Publisher Return
- 路由键写错或者交换机没有绑定队列),此时通过PublisherReturn返回路由异常原因,然后返回ACK
-
ACK,告知投递成功
-
如果队列是持久化的,消息投递到MQ服务器,并且入队完成且保存到磁盘之后,返回ACK,告知投递成功
-
其他情况都会返回NACK
spring:
rabbitmq:
addresses: xxx.xx.xx.xx
port: 5672
username: xx
password: xx
virtual-host: /xx
connection-timeout: 1s #设置MQ的连接超时时间
template:
retry:
max-attempts: 3 #最大重试次数
enabled: true # 开启重试机制
multiplier: 1 #失败后下次等待时长倍数,下次等待时长=initial-interval * multiplier
initial-interval: 1000ms # 失败后的初始等待时间
publisher-returns: true # 开启publisher return机制
publisher-confirm-type: correlated #
说明:
publish-confirms: 开启publish-confirm功能,确认回调,springboot 2.2.0之后不用了,被publish-confirm-type替换了
publish-confirm-type:开启publisher-confirm,这里支持三种类型:
none: 不开启生产者确认
simple:同步等待confirm结果,直到超时
correlated:异步回调,定义ConfirmCallback,MQ返回结果时会回调这个ConfirmCallback
publish-returns:开启publish-return功能,同样是基于callback机制,不过是定义ReturnCallback
https://blog.csdn.net/qq_29385297/article/details/127545272
@Configuration
@Slf4j
public class RabbitMqReturnConfig implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
/**
*
* @param message 发送的消息
* @param replyCode 应答码
* @param replyText 原因
* @param exchange 交换机
* @param routingKey 路由键
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.info("消息发送失败: 应答码={}, 原因={}, 交换机={},路由键={},消息={}",
replyCode,replyText,exchange,routingKey,message.getBody().toString());
}
});
}
}
@RequestMapping("/sendMessageConfirm")
public String sendMessageConfirm(String message){
// 直接向队列里面发送消息
CorrelationData correlationData=new CorrelationData();
correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
/**
* 此处的失败,并不代表nack,此处的失败是spring内部处理的时候失败了
* @param throwable
*/
@Override
public void onFailure(Throwable throwable) {
// future发送异常时的处理逻辑,一般不会发生直接打印就行
log.error("on failure:{}",throwable);
}
/**
* 代表MQ的回调成功,但并不代表消息发送的结果
* @param confirm
*/
@Override
public void onSuccess(CorrelationData.Confirm confirm) {
if(confirm.isAck()){
log.info("消息发送成功,收到ACK");
}else {
log.info("消息发送失败,收到NACK,原因:{}",confirm.getReason());
}
}
});
Map<String,Object> map=new HashMap<>();
map.put("name","张三");
map.put("address","浙江杭州");
rabbitTemplate.convertAndSend(BootMqConstant.TOPICS_EXCHANGE_NAME,"object.hahha",map,correlationData);
return "ok";
}
上述代码发送了两条消息到topics_object_queue
队列中,发送成功之后,生产者被回调了两次
ack
运行结果