RabbitMQ------消息可靠性投递
一。什么是消息可靠性投递?
1.保证消息百分百发送到消息队列中去
a.保证mq节点成功接受消息
b.消息发送端需要接受到mq服务端接受到消息的确认应答
c.完善的消息补偿机制,发送失败的消息可以再感知并二次处理
二。RabbtiMQ消息投递路径
1.生产者-->交换机->队列->消费者 2.通过两个的点控制消息的可靠性投递 a.生产者到交换机 通过confirmCallback b.交换机到队列 通过returnCallback 3.建议 开启消息确认机制以后,保证了消息的准确送达,但由于频繁的确认交互, rabbitmq 整体效率变低,吞吐量下降严重,不是非常重要的消息真心不建议用消息确认机制
三。生产者到交换机
1.通过confirmCallback实现 2.生产者投递消息后,如果Broker收到消息后,会给生产者一个ACK。生产者通过ACK,可以确认这条消息是否正常发送到Broker,这种方式是消息可靠性投递的核心 3.开启confirmCallback #旧版,确认消息发送成功,通过实现ConfirmCallBack接口,消息发送到交换器Exchange后触发回调 spring.rabbitmq.publisher-confirms=true #新版,NONE值是禁用发布确认模式,是默认值,CORRELATED值是发布消息成功到交换器后会触发回调方法 spring.rabbitmq.publisher-confirm-type: correlated
代码:
部分代码可参考:
https://www.cnblogs.com/tianhengblogs/p/15341670.html
//测试消息回调确认 @GetMapping("/confirm") public String testConfirm(){ rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() { /** * @Description * @param correlationData 配置 * @param ack 交换机是否接收到消息 true: 成功 false: 失败 * @param cause 失败原因 * @return */ @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { //判断 if (ack){ //更新数据库,消息状态为成功 TODO }else { //更新数据库,消息状态为失败 TODO } //打印信息 System.out.println("correlationData: " + correlationData); System.out.println("ack: " + ack); System.out.println("cause: " + cause); } }); //数据库新增一条消息记录,状态为发送 TODO //发送消息 rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME, "order.new", "新订单消息"); //模拟异常 //rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME + "123", "order.new", "新订单消息"); return "success"; }
四。交换机到队列
1.通过returnCallback 2.消息从交换器发送到对应队列失败时触发 3.两种模式 a.交换机到队列不成功,则丢弃消息(默认) b.交换机到队列不成功,返回给消息生产者,触发returnCallback 4.开启returnCallback //为true,则交换机处理消息到路由失败,则会返回给生产者
template.setMandatory(true);
//或者配置文件旧版本
spring.rabbitmq.template.mandatory=true
//新版本
spring.rabbitmq.publisher-returns=true
代码:
部分代码可参考:
https://www.cnblogs.com/tianhengblogs/p/15341670.html
@GetMapping("return") public String testReturn(){ rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() { @Override public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { //打印信息 System.out.println("message: " + message.toString()); } }); //发送消息 // rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME, "order.new", "新订单消息"); //模拟异常 rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME, "123.order.new", "新订单消息"); return "success"; }