RabbitMq学习(六)消息确认之接收确认

为什么需要接收确认

RabbitMQ默认会在消息被消费者接收后,立即确认。但存在丢失消息的可能,如果消费端消费逻辑抛出异常,也就是消费端没有处理成功这条消息,那么就相当于丢失了消息。
另外一种情况就是,我们在spring中处理消息时,即使消息处理没出异常,但是后续代码出异常造成回滚,这样其实也相当于丢失消息。
所以一般情况下,手动确认要比较好一些。

消息确认模式

AcknowledgeMode.NONE:自动确认
AcknowledgeMode.AUTO:根据情况确认
AcknowledgeMode.MANUAL:手动确认

开启消息手动确认

配置文件中:

spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual

配置类:

@Bean
public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
	SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
	factory.setConnectionFactory(connectionFactory);
	//使用jackson进行消息序列与反序列
	factory.setMessageConverter(new Jackson2JsonMessageConverter());
	factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 开启手动 ack
	return factory;
}

确认消息的API

通过com.rabbitmq.client.Channel中的方法来进行消息确认

//确认消费成功
void basicAck(long deliveryTag, boolean multiple) throws IOException;
//确认消费失败
void basicNack(long deliveryTag, boolean multiple, boolean requeue)
            throws IOException;
//拒绝消息        
void basicReject(long deliveryTag, boolean requeue) throws IOException;

关于参数:
deliveryTag:RabbitMQ 向该 Channel 投递的这条消息的唯一标

multiple:是否批量处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息
requeue:是否重新放入队列

消息消费过程中异常处理

大致有以下三种处理方式

  1. 内部catch后直接处理,然后使用channel对消息进行确认。
    这种需要设置手动处理,然后用channel进行消息确认。这种操作方式,若是消费出现异常,调用basicNack方法时的参数requeue若是true,消息就会一直被重新放入队列,然后消费,然后异常,死循环。
    处理方式:
    为了避免消息处理异常造成死循环,我们可以将requeue设置成fasle,这时消息会进入“死信”队列。然后我们可以监听死信队列来做异常处理。
    我们可以在设置队列时指定死信队列的交换机和路由key:

    //声明队列,并给队列增加x-dead-letter-exchange和x-dead-letter-routing-key参数,用于指定死信队列的路由和routingKey
    @Bean
    public Queue queue(){
        Map<String, Object> args = new HashMap<String, Object>();
        args.put("x-dead-letter-exchange",IntegralConstant.DEAD_EXCHANGE_NAME);
        args.put("x-dead-letter-routing-key",IntegralConstant.DEAD_ROUTING_KEY);
        return new Queue(IntegralConstant.QUEUE_NAME, true, false, false, args);
    }
    

    然后我们在进行消息确认时就可以做如下操作:

    ```
    /消息确认时使用nack,并且requeue参数传false
    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
    ```
    

    顺便提一下消息变成死信的情况:
    消息被拒绝(basic.reject/ basic.nack)并且requeue=false
    消息TTL过期(参考:RabbitMQ之TTL(Time-To-Live 过期时间))
    队列达到最大长度

  2. 配置RepublishMessageRecoverer将处理异常的消息发送到指定队列专门处理或记录
    注意,这是在消息方法中不处理异常的情况下,spring.rabbitmq.listener.retry配置的重试次数用完以后还是抛异常的话才会调用这个RepublishMessageRecoverer来处理

    @Bean
    public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
        return new RepublishMessageRecoverer(rabbitTemplate, "errorExchange", "errorRoutingKey");
    }
    
  3. ErrorHandler
    利用@RabbitListener中的属性errorHandler实现一个异常监听处理器:

    /**
    	 * 
    	 * @return
    	 */
    	@Bean
    	public RabbitListenerErrorHandler rabbitListenerErrorHandler() {
    		return (amqpMessage, message, exception) -> {
    			System.out.println("进入handler");
    			System.out.println(new String(amqpMessage.getBody()));
    			return null;
    		};
    	}
    

总结

  1. 若是开启的自动确认,可以使用第二种和第三种方法进行消费异常的处理。
  2. 若是开启的手动确认,监听的方法内部必须使用channel进行消息确认,包括消费成功或消费失败,使用第一种方法即可。
  3. 手动确认情况下,推荐在消息消费失败时,将消息放入死信队列(requeue=false)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ 中,消费者接收消息后,需要发送 ACK 确认接收,以告知 RabbitMQ消息已经被正确地接收并处理。如果消费者接收消息后没有发送 ACK 确认接收,那么 RabbitMQ 将会认为该消息没有被正确地处理,会重新将消息发送给其他消费者。 在 RabbitMQ 中,发送 ACK 确认接收的方式有两种: 1. 自动确认模式 在自动确认模式下,当消费者接收消息后,RabbitMQ 会自动发送 ACK 确认接收,不需要手动发送 ACK。这种模式下,如果消息处理失败,那么消息就会被丢弃,因此,只有在消息处理相对简单、不需要进行复杂的错误处理时,才适合使用自动确认模式。 2. 手动确认模式 在手动确认模式下,当消费者接收消息后,需要手动发送 ACK 确认接收。如果消息处理失败,可以发送 NACK 拒绝接收,然后重新将消息发送给其他消费者。手动确认模式可以保证消息的可靠性和一致性,但需要消费者手动发送 ACK、NACK 等命令,因此比较复杂。 在 RabbitMQ 的 Java 客户端中,可以使用 channel.basicAck() 方法手动发送 ACK 确认接收,使用 channel.basicNack() 方法发送 NACK 拒绝接收。例如,以下代码演示了如何手动发送 ACK 确认接收: ```java channel.basicConsume(queueName, false, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { // 处理消息 // ... // 手动发送 ACK 确认接收 channel.basicAck(envelope.getDeliveryTag(), false); } }); ``` 在上述代码中,第二个参数设置为 false,表示关闭自动确认模式,需要手动发送 ACK 确认接收。当消息处理完成后,调用 channel.basicAck() 方法发送 ACK 确认接收。这样可以保证消息被正确地处理,并且可以避免消息丢失的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值