15.RabbitMQ 消费端手动ACK消息确认机制

本文详细介绍了RabbitMQ中消费者消息确认(ack)的三种模式:自动确认、手动确认和异常情况确认。手动确认允许在业务处理成功后才确认消息,确保消息可靠性。文中给出了配置消费者为手动确认的示例,并展示了如何在处理异常时使用basicNack拒签消息,使消息重新进入队列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  ack——acknowledge(vt. 承认;答谢;报偿;告知已收到;确认的意思),在RabbitMQ中指代的是消费者收到消息后确认的一种行为,关注点在于消费者能否实际接收到MQ发送的消息。

  其提供了三种确认方式:

  自动确认acknowledge=“none”:当消费者接收到消息的时候,就会自动给到RabbitMQ一个回执,告诉MQ我已经收到消息了,不在乎消费者接收到消息之后业务处理的成功与否。

  手动确认acknowledge=“manual”:当消费者收到消息后,不会立刻告诉RabbitMQ已经收到消息了,而是等待业务处理成功后,通过调用代码的方式手动向MQ确认消息已经收到。当业务处理失败,就可以做一些重试机制,甚至让MQ重新向消费者发送消息都是可以的。

  根据异常情况确认acknowledge=“auto”:该方式是通过抛出异常的类型,来做响应的处理(如重发、确认等)这种方式比较麻烦。

  当消息一旦被消费者接收到,会立刻自动向MQ确认接收,并将响应的message从RabbitMQ消息缓存中移除,但是在实际的业务处理中,会出现消息收到了,但是业务处理出现异常的情况,在自动确认的模式下,该条业务处理失败的message就相当于被丢弃了。如果设置了手动确认,则需要在业务处理完成之后,手动调用channel.basicAck(),手动的签收,如果业务处理失败,则手动调用channel.basicNack()方法拒收,并让MQ重新发送该消息。

  如果不做任何关于acknowledge的配置,默认就是自动确认签收的。

  1、消费者配置:

server:
  port: 81

spring:
  rabbitmq:
    host: www.996.com
    port: 5672
    username: rabbitadmin
    password: rabbitadmin
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual #手动

  2、消费者接口方法:

/**
 * 测试 ACK
 * @param message
 */
public void receiveMessage(String message);

  3、消费者接口方法实现:

/**
 * 测试 ACK
 * @param message
 */
@Override
@RabbitListener(queues = {RabbitMqConfig.DIRECT_QUEUE})
public void receiveMessage(String message) {
    System.out.println("接收到的MQ消息:"+message);
    //处理业务
    System.out.println("处理业务");
}

  4、生产者发送队列消息

/**
 * convertAndSend(String exchange, String routingKey, Object object),c
 *
 * @param message
 * @return
 */
@Override
public void sendMessage(String message) {
    CorrelationData correlationData = new CorrelationData("1");
    rabbitTemplate.convertAndSend(RabbitMqConfig.DIRECT_EXCHANGE,RabbitMqConfig.DIRECT_ROUTINGKEY,message,correlationData);
}

  5、队列
在这里插入图片描述
  6、消费者接收队列消息成功,但队列中的消息并未删除,只是状态变更为未确认状态
在这里插入图片描述
  7、更改消息接收方法,进行手动ACK确认

/**
 * 测试 ACK
 * @param message
 */
@Override
@RabbitListener(queues = {RabbitMqConfig.DIRECT_QUEUE})
public void receiveMessage(String message, Channel channel,@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {

    try {
        System.out.println("接收到的MQ消息:"+message);
        //处理业务
        System.out.println("处理业务");
        //手动Ack
        /**
         * 手动Ack参数说明
         * basicAck(long deliveryTag, boolean multiple)
         * deliveryTag:批量处理的标号,举例:这个队列现在有5条消息要消费,那么这批数据会标号从1-5递增,5的时候就会手动Ack  multiple:是否批量处理
         *
         */
        System.out.println("deliveryTag:" + deliveryTag);
        channel.basicAck(deliveryTag,true);
    }catch (Exception e){
        e.getMessage();
    }

}

  8、消费者接收队列消息并手动ACK确认
在这里插入图片描述
  9、若业务中处理异常是可以拒签的,模拟业务

/**
 * 测试 ACK
 * @param message
 */
@Override
@RabbitListener(queues = {RabbitMqConfig.DIRECT_QUEUE})
public void receiveMessage(String message, Channel channel,@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {

    try {
        System.out.println("接收到的MQ消息:"+message);
        //处理业务
        System.out.println("处理业务"+1/0);
        //手动Ack
        /**
         * 手动Ack参数说明
         * basicAck(long deliveryTag, boolean multiple)
         * deliveryTag:批量处理的标号,举例:这个队列现在有5条消息要消费,那么这批数据会标号从1-5递增,5的时候就会手动Ack  multiple:是否批量处理
         *
         */
        System.out.println("deliveryTag:" + deliveryTag);
        channel.basicAck(deliveryTag,true);
    }catch (Exception e){
        e.printStackTrace();
        /**
         * basicNack(long deliveryTag, boolean multiple, boolean requeue)
         * requeue:是否送回队列
         */
        try {
            channel.basicNack(deliveryTag,false,true);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }

}

  10、测试,异常后消息会被送回队列再次被监听到继续消费,重试消费默认3次后便不再消费
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值