MQ的相关问题

消息可靠性问题

在这里插入图片描述

用mq做消息代理,当mq的信息发送不到交易服务时,会造成消息的丢失问题。
消息丢失的可能性:
1.支付服务到消息代理的过程中消息丢失。
2.消息代理(MQ)导致消息丢失。
3.消息代理到交易服务过程中消息丢失。

生产者重连

有时候由于网络波动,可能会出现客户端连接MQ失败的情况。通过配置我们可以开启连接失败后的重连机制:

spring:
  rabbitmq:
    connection-timeout: 1s #设置mq的连接超时时间
    template:
      retry:
        enabled: true #开启超时重试机制
        initial-interval: 1000ms  #失败后的初始等待时间
        multiplier: 2  #失败后下次的等待时长倍数,下次等待时长  = initial-interval * multiplier
        max-attempts: 3 #最大重试次数

注意:
当网络不稳定的时候,利用重试机制可以有效提高消息发送的成功率。不过SpringAMQP提供的重试机制是阻塞式的重试,也就是说多次重试等待的过程中,当前线程是被阻塞的,会影响业务性能。
如果对于业务性能有要求,建议禁用重试机制。如果一定要使用,请合理配置等待时长和重试次数,当然也可以考虑使用异步线程来执行发送消息的代码。

在这里插入图片描述

这里时间间隔2s,3s下一次的间隔必为5s

生产者确认

RabbitMQ给出了Publisher Confirm和Publisher Return两种确认机制.开启确认机制后,在MQ成功收到消息后会返回确认消息给生产者。返回的结果有以下几种情况。

  • 消息投递到了MQ,但是路由失败。此时会通过PublisherReturn返回路由异常原有,然后返回ACK,告知投递成功。
  • 临时消息投递到MQ,并且入队成功,返回ACK,告知投递成功
  • 持久消息投递到了MQ,并且入队完成持久化,返回ACK,告知投递成功。
  • 其他情况都会返回NACK,告知投递失败。

在这里插入图片描述

SpringAMQP实现生产者确认

1.在publisher这个微服务的application.yml中添加配置

spring:
  rabbitmq:
    publisher-confirm-type: correlated 
    publisher-returns: true

配置说明:

  • 这里publisher-confirm-type有三种模式可选:
    none: 关闭confirm机制
    simple: 同步阻塞等待MQ的回执消息
    correlated: MQ异步回调方式返回回执消息

2.增加配置bean


@Configuration
@Slf4j
public class CommonConfig implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取rabbitTemplate
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        //设置ReturnCallback
        rabbitTemplate.setReturnCallback((message,replyCode,replyText,exchange,routingKey)->{
            log.info("消息发送失败,应答码{},原因{},交换机{},路由键{},消息{}",replyCode,replyText,exchange,routingKey,message);
        });
    }
}

随着版本迭代更新,也可以换一种写法:

@Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取rabbitTemplate
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        //设置ReturnCallback
        rabbitTemplate.setReturnsCallback(rmsg -> log.info("消息发送失败,应答码是{},原因是{},交换机是{},路由键是{},消息是{}",rmsg.getReplyCode()
                ,rmsg.getReplyText(),rmsg.getExchange(),rmsg.getRoutingKey(),rmsg.getMessage()));
    }

3.调用时增加

 @Test
    public void testPayQueue() {
        //1.创建CorrelationData
        CorrelationData cd = new CorrelationData();
        //2.给Future添加ConfirmCallback
        cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            @Override
            public void onFailure(Throwable ex) {
                //Future发生异常时的处理逻辑,基本不会触发
                log.info("handle message ack fail",ex);
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                if (result.isAck()){
                    log.info("发送消息成功,收到ack!");
                }else {
                    log.error("发送消息失败,收到nack,reason:{}",result.getReason());
                }
            }
        });
        //发送消息
        rabbitTemplate.convertAndSend("pay.topic","pay.success","202405200002",cd);
     //   System.out.println("这里是阻塞式的重试");
    }

总结

只要消息到达了mq就是ack

如何处理生产者的确认消息?

  • 生产者确认需要额外的网络和系统资源开销,尽量不要使用
  • 如果一定要使用,无需开启Publisher-Return机制,因为一般路由失败是自己业务问题
  • 对于nack消息可以有限次数重试,依然失败则记录异常消息
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值