RabbitMQ–集成Springboot–06–SpringRetry重试


1、介绍

rabbitMQ有个方法channel.basicNack()能够让消息回到队列中,这样可以实现重试。但是这样没有明确重试次数,如果当前的消息一直重试的话,则后面的消息就会堆积起来,导致后面的消息无法消费。

这是一个致命的缺点。因此这就需要设置重试次数来解决这种问题。下面提供几种解决方案。

  1. 使用redis或者mongo等第三方存储当前重试次数。
  2. 在header中添加重试次数,并且使用channel.basicPublish() 方法重新将消息发送出去后将重试次数加1。
  3. 使用spring-rabbit中自带的retry功能

2、手动确认模式说明

  1. 监听的方法内部必须使用channel进行消息确认,包括消费成功或消费失败
  2. 如果不手动确认,也不抛出异常,消息不会自动重新推送(包括其他消费者),因为对于rabbitmq来说始终没有接收到消息消费是否成功的确认,并且Channel是在消费端有缓存的,没有断开连接
  3. 如果rabbitmq断开,连接后会自动重新推送(不管是网络问题还是宕机)
  4. 如果消费端应用重启,消息会自动重新推送
  5. 如果消费端处理消息的时候宕机,消息会自动推给其他的消费者
  6. 如果监听消息的方法抛出异常,消息会按照listener.retry的配置进行重发,但是重发次数完了之后还抛出异常的话,消息不会重发(也不会重发到其他消费者),只有应用重启后会重新推送。因为retry是消费端内部处理的,包括异常也是内部处理,对于rabbitmq是不知道的(可使用死信队列)
  7. spring.rabbitmq.listener.retry配置的重发是在消费端应用内处理的,不是rabbitqq重发
  8. 可以配置MessageRecoverer对异常消息进行处理,此处理会在listener.retry次数尝试完并还是抛出异常的情况下才会调可以配置MessageRecoverer对异常消息进行处理,默认有两个实现

2.1、配置MessageRecoverer

//RepublishMessageRecoverer:将消息重新发送到指定队列,需手动配置,如:
@Bean
public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
    return new RepublishMessageRecoverer(rabbitTemplate, "exchangemsxferror", "routingkeymsxferror");
}
//RejectAndDontRequeueRecoverer:如果不手动配置MessageRecoverer,会默认使用这个,实现仅仅是将异常打印抛出,源码如下:
public class RejectAndDontRequeueRecoverer implements MessageRecoverer {
    protected Log logger = LogFactory.getLog(RejectAndDontRequeueRecoverer.class);
    @Override
    public void recover(Message message, Throwable cause) {
    	if (this.logger.isWarnEnabled()) {
            this.logger.warn("Retries exhausted for message " + message, cause);
    	}
    	throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message);
    }
}

2.2、retry yml配置

rabbitmq:
    username: guest
    password: guest
    port: 5672
    host: localhost
    publisher-confirms: true #  消息发送到交换机确认机制,是否确认回调
    publisher-returns: true  #  消息发送到交换机确认机制,是否返回回馈
    listener:       # 开启ACK
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual
        retry:
          enabled: true         #  允许消息消费失败的重试
          max-attempts: 6       # 消息最多消费次数6次
          initial-interval: 1000ms # 消息多次消费的间隔1秒
          max-interval: 1200000ms #重试最大时间间隔(单位毫秒)
          multiplier: 2 #应用于上一重试间隔的乘数 即重试时间为  上次重试时间*2
          stateless: true
          default-requeue-rejected: false  #  设置为false,会丢弃消息或者重新发布到死信队列