java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot RabbitMQTemplate消费者确认机制

SpringBoot RabbitMQTemplate消费者确认机制怎么选?

作者:Quare_feifei

本文详解SpringBoot中RabbitMQTemplate的消费者消息确认机制,包括manual、auto、none三种模式的区别,同时介绍消费者失败重试与失败策略,助你避免消息丢失和无限重试,确保系统可靠

这里主要是针对springboot中的rabbitmqtemplate来说的

基础代码以查看此专栏相关文章

消费者消息确认

RabbitMQ是阅后即焚机制,RabbitMQ确认消息被消费者消费后会立刻删除。

而RabbitMQ是通过消费者回执来确认消费者是否成功处理消息的:消费者获取消息后,应该向RabbitMQ发送ACK回执,表明自己已经处理消息。

设想这样的场景

这样,消息就丢失了。因此消费者返回ACK的时机非常重要。

SpringAMQP则允许配置三种确认模式

由此可知:

一般,我们都是使用默认的auto即可。

配置方式

spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: 确认模式

消费者失败重试机制

当消费者出现异常后,消息会不断requeue(重入队)到队列,再重新发送给消费者,然后再次异常,再次requeue,无限循环,导致mq的消息处理飙升,带来不必要的压力

本地重试

我们可以利用Spring的retry机制,在消费者出现异常时利用本地重试,而不是无限制的requeue到mq队列。

修改consumer服务的application.yml文件,添加内容:

spring:
  rabbitmq:
    listener:
      simple:
        retry:
          enabled: true # 开启消费者失败重试
          initial-interval: 1000ms # 初识的失败等待时长为1秒
          multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-interval
          max-attempts: 3 # 最大重试次数
          stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false

重启consumer服务,重复之前的测试。可以发现:

结论:

失败策略

在之前的测试中,达到最大重试次数后,消息会被丢弃,这是由Spring内部机制决定的。

在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有MessageRecovery接口来处理,它包含三种不同的实现:

比较优雅的一种处理方案是RepublishMessageRecoverer,失败后将消息投递到一个指定的,专门存放异常消息的队列,后续由人工集中处理。

1)在consumer服务中定义处理失败消息的交换机和队列

    @Bean("error_direct")
    public  DirectExchange errorMessageExchange(){
        return new DirectExchange("error_direct");
    }
    @Bean("error_queue")
    public Queue errorQueue(){
        return new Queue("error_queue",true);
    }
    @Bean
    public Binding bindingerror(DirectExchange error_direct,Queue error_queue){
        return  BindingBuilder.bind(error_queue).to(error_direct).with("error");
    }

2)定义一个RepublishMessageRecoverer,关联队列和交换机

@Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate,"error_direct","error");
    }

完整代码

    @Bean("error_direct")
    public  DirectExchange errorMessageExchange(){
        return new DirectExchange("error_direct");
    }
    @Bean("error_queue")
    public Queue errorQueue(){
        return new Queue("error_queue",true);
    }
    @Bean
    public Binding bindingerror(DirectExchange error_direct,Queue error_queue){
        return  BindingBuilder.bind(error_queue).to(error_direct).with("error");
    }
    @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate,"error_direct","error");
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文