RabbitMQ消费失败重试策略、及重试策略应用场景详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言
RabbitMQ消费者一般情况下如果消费失败出现异常那么消费端默认是无限重试消费这样就会带来非常不好的一个情况就是陷入死循环一直报错一直重试。所以我们需要对消费异常重试次数、重试间隔时间进行限制

一、限制消费异常重试次数、重试间隔时间

1、配置限制策略如下

rabbitmq:
    host: xxx
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        default-requeue-rejected: false
        acknowledge-mode: manual  # 确认模式为手动确认-需要在代码中手动ACK
        retry:
          enabled: true           # 开启消费者出现异常情况下进行重试消费默认false
          max-attempts: 5         # 最大重试次数默认为3
          initial-interval: 3000  # 重试间隔时间默认1000(单位毫秒)

其中 retry 节点及以下的属性就是重试策略

2、验证重试策略是否生效
这里使用一张 user 信息表作演示

【1】演示代码

    @RabbitListener(queues = {MqConstants.DIRECT_QUEUE_1})
    public void listenerDirectQueue1(Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        //验证消费失败(出现异常)重试策略 start
        String msgBody = new String(message.getBody());
        System.out.println("消费者接收到消息【" + msgBody + "】");
        int i = 1 / 0;
        channel.basicAck(deliveryTag, false);
        //验证消费失败(出现异常)重试策略 end
    }

模拟了一个除数为0的异常

【2】演示结果

从控制台输出可以看出异常后尝试了5次后仍然失败就放弃重试符合预期结果

二、消息消费异常重试策略应用场景并不是所有消息异常后都需要重试

1、说明
【1】比如我们调用第三方接口、或者调用别的服务的接口那么这时候出现异常要不要重试当然要重试因为调用接口异常可能是网络波动导致并不是业务代码异常所以重试后可能就可以正常调用
【2】比如我们在消费过程中业务代码出现异常(空指针、除数为0等)这类代码不健壮导致的异常那么这时候需要重试吗当然不需要重试因为业务代码异常就算重试再多次也依然会异常代码异常需要发版修复解决所以重试没有意义。这种情况我们可以把代码块 try catch 一下

    @RabbitListener(queues = {MqConstants.DIRECT_QUEUE_1})
    public void listenerDirectQueue1(Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        String msgBody = new String(message.getBody());

        //验证消费失败(出现异常)重试策略 start
        try {
            System.out.println("消费者接收到消息【" + msgBody + "】");
            int i = 1 / 0;
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            log.info("异常消息" + msgBody);
            //此时可以把异常消息写入表中以供人工或定时任务做重试补偿
            channel.basicAck(deliveryTag, false);
        }
        //验证消费失败(出现异常)重试策略 end
    }

 可以看见异常被捕捉了所以没有触发重试策略

小结
在 catch 块中不要抛出异常就不会触发重试策略在 catch 块中我们把该条消息记录到日志数据表或者其他特定的表以供过后人工或定时任务单独处理异常消息补偿即可

2、应用场景总结
【1】类似调用第三方接口这种场景出现异常需要重试
【2】业务代码出现异常(空指针、除数为0等)这类代码不健壮导致的异常不需要重试没有意义
【3】异常不需要触发重试策略的消息需要把该条消息记录到日志数据表或者其他特定的表以供过后人工或定时任务单独处理异常消息补偿

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: RabbitMQ