RabbitMQ的ACK确认机制保障消费端消息的可靠性详解

 更新时间:2023年12月12日 10:12:31   作者:warybee  
这篇文章主要介绍了RabbitMQ的ACK确认机制保障消费端消息的可靠性详解,简单来说,就是你必须关闭 RabbitMQ 的自动ack ,可以通过一个 api 来调用就行,然后每次你自己代码里确保处理完的时候,再在程序里 ack 一把,需要的朋友可以参考下

1. 概述

如果消费端在你消费的时候,刚消费到,还没处理,结果进程挂了,比如重启了,那么就尴尬了,RabbitMQ 认为你都消费了,这数据就丢了。这个时候得用 RabbitMQ 提供的 ack 机制,简单来说,就是你必须关闭 RabbitMQ 的自动ack ,可以通过一个 api 来调用就行,然后每次你自己代码里确保处理完的时候,再在程序里 ack 一把。这样的话,如果你还没处理完,不就没有 ack 了?那 RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把这个消费分配给别的 consumer 去处理,消息是不会丢的。

生产端消息可靠性保证可以使用RabbitMQ的confirm机制。

2. ACK机制与消费端消息补偿机制

把channel.basicConsume(...)方法的autoAck参数改为false

channel.basicAck(long deliveryTag, boolean multiple);方法,消费成功签收

参数说明:

  • deliveryTag:消息标识
  • multiple:是否批量签收

basicNack(long deliveryTag, boolean multiple, boolean requeue) ,消息消费失败

参数说明:

  • deliveryTag:消息标识
  • multiple:是否批量签收
  • requeue:true 消息会重回队列,false 消息会进入到死信队列

3. 代码演示

生产端

 public static void main(String[] args) throws Exception{
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //设置虚拟主机
        connectionFactory.setVirtualHost("/");
        //创建一个链接
        Connection connection = connectionFactory.newConnection();
        //创建channel
        Channel channel = connection.createChannel();
        String exchangeName="test_ack_exchange";
        String routeKey="ack.test";
        for (int i=0;i<5;i++){
            Map<String, Object> headers = new HashMap<String, Object>();
            //演示重回队列机制,使用num==0的消息签收失败重回队列
            headers.put("num", i);
            AMQP.BasicProperties properties=new AMQP.BasicProperties().builder()
                    .deliveryMode(2)
                    .contentEncoding("UTF-8")
                    .headers(headers)
                    .build();
            String msg="RabbitMQ send message ack test!"+i;
            channel.basicPublish(exchangeName,routeKey,properties,msg.getBytes());
        }
    }

消息端

public static void main(String[] args) throws  Exception{
        System.out.println("======消息接收start==========");
        ConnectionFactory connectionFactory=new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //设置虚拟主机
        connectionFactory.setVirtualHost("/");
        //创建链接
        Connection connection = connectionFactory.newConnection();
        //创建channel
        Channel channel = connection.createChannel();
        String exchangeName="test_ack_exchange";
        String exchangeType="topic";
        //声明Exchange
        channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
        String queueName="test_ack_queue";
        //声明队列
        channel.queueDeclare(queueName,true,false,false,null);
        String routeKey="ack.#";
        //绑定队列和交换机
        channel.queueBind(queueName,exchangeName,routeKey);
        /**
         * autoAck:false  设置为手工签收
         */
        channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    System.out.println("接收到消息::"+new String(body));
                    try {
                        Thread.sleep(3000); //休眠5秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //演示重回队列机制,使用num==0的消息签收失败重回队列
                    if((Integer)properties.getHeaders().get("num") == 0) {
                        /**
                         * 参数说明:1、消息标识  2、是否批量签收  3、是否重回队列
                         */
                        channel.basicNack(envelope.getDeliveryTag(), false, true);
                    } else {
                        channel.basicAck(envelope.getDeliveryTag(), false);
                    }
                }
            });
    }

运行代码以上后,由于在消费端,设置了第一条消息,签收失败重回队列,在RabbitMQ控制台中我们可以看到始终有一条消息未签收确认

在这里插入图片描述

到此这篇关于RabbitMQ的ACK确认机制保障消费端消息的可靠性详解的文章就介绍到这了,更多相关RabbitMQ的ACK确认机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Spring Expression Language (SpEL)全面解析表达式

    使用Spring Expression Language (SpEL)全面解析表达式

    这篇文章主要介绍了使用Spring Expression Language (SpEL)全面解析表达式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • maven settings.xml文件的存放及配置(包含了配置阿里云镜像)

    maven settings.xml文件的存放及配置(包含了配置阿里云镜像)

    本文详细解释了Maven中settings.xml文件的存放位置,以及用户级别和全局级别的区别,重点介绍了localRepository、交互模式、离线模式、插件组、代理设置、服务器认证、镜像列表和激活profiles的使用方法,感兴趣的可以了解一下
    2025-09-09
  • 排序算法的Java实现全攻略

    排序算法的Java实现全攻略

    这篇文章主要介绍了排序算法的Java实现,包括Collections.sort()的使用以及各种经典算法的Java代码实现方法总结,超级推荐!需要的朋友可以参考下
    2015-08-08
  • Spring Boot jar中没有主清单属性的解决方法

    Spring Boot jar中没有主清单属性的解决方法

    这篇文章主要介绍了Spring Boot jar中没有主清单属性的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • java对接Pinata上传文件到IPFS全过程

    java对接Pinata上传文件到IPFS全过程

    本文详细介绍了如何使用Pinata API将文件上传到IPFS网络,首先登录Pinata官网并生成JWT令牌,然后在项目中导入OkHttp依赖并编写代码,通过调用Pinata的API接口上传文件,最后,通过Swagger调试接口并获取上传的文件CID
    2025-11-11
  • Java实现读取CSV文件并将数据放入对象

    Java实现读取CSV文件并将数据放入对象

    CSV文件是一种常见的数据存储格式,广泛应用于数据交换,日志记录和表格数据处理,在Java开发中,读取CSV文件并将数据映射到对象中是常见的需求,本文将详细介绍几种常见方法,有需要的可以了解下
    2025-06-06
  • SpringBoot中的MongoTemplate的各种条件查询示例详解

    SpringBoot中的MongoTemplate的各种条件查询示例详解

    这篇文章主要介绍了SpringBoot中的MongoTemplate的各种条件查询示例详解,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借价值,需要的朋友参考下吧
    2024-01-01
  • springboot配置多数据源的一款框架(dynamic-datasource-spring-boot-starter)

    springboot配置多数据源的一款框架(dynamic-datasource-spring-boot-starter

    dynamic-datasource-spring-boot-starter 是一个基于 springboot 的快速集成多数据源的启动器,今天通过本文给大家分享这款框架配置springboot多数据源的方法,一起看看吧
    2021-09-09
  • 使用纯Java实现一个WebSSH项目的示例代码

    使用纯Java实现一个WebSSH项目的示例代码

    这篇文章主要介绍了使用纯Java实现一个WebSSH项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Java Runtime的使用详解

    Java Runtime的使用详解

    这篇文章主要介绍了Java Runtime的使用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论