rabbitmq重复确认导致消息丢失

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: rabbitmq重复确认导致消息丢失

rabbitmq 在应用场景中,大多采用工作队列 work-queue的模式。

在一个常见的工作队列模式中,消费者 worker 将不断的轮询从队列中拉取最新消息,当队列负载压力增大时允许添加多个worker 进行处理。

然而执行一个任务可能需要相当的时长,这是由业务特性所决定的;如果 worker执行任务过程中出现异常甚至宕机,此时消息便会丢失,这是简单消息队列难以解决的问题。

rabbitmq 采用了消息确认机制来防止此类问题,在该机制中,worker需要向 MQ Server 返回 ACK响应以表示消息已确认处理;

在以下情况下,rabbitmq 会对消息进行重新投递:

  1. client 未响应ACK, 主动关闭 Channel;
  2. client 未响应ACk, 网络异常断开;

消息的重发机制没有超时限制,只要client 不响应ACK,那么会一直投递;

如果启用了消息持久化机制,那么消息将有进一步的保障。

问题描述及分析

1 客户端为简化应答处理,可以设置自动应答选项,如:

boolean autoAck = false;
 channel.basicConsume(TASK_QUEUE_NAME, autoAck, consumer);

2 如果不启用自动应答,需要应用代码手动进行应答:

try {
      doWork(message);
    } finally {
      logger.info(" xxx work done");
      channel.basicAck(envelope.getDeliveryTag(), false);
    }

3 当两种方案同时存在

由于客户端的编码失误,先启用了自动应答选项,又在应用代码执行了应答的代码:

// enable autoAck
     boolean autoAck = true;
     consumerChannel.basicConsume(queueName, autoAck, this);
     //...
     // snipper from Consumer.handleDelivery method
     // send ack to server  
     try {
            consumerChannel.basicAck(deliveryTag, true);
        } catch (Exception e) {
     }

多了一次确认,应用代码貌似一切如常。 但在频繁进行消息收发测试时发现 消息存在随机性丢失处理的情况!

检查 rabbitmq server日志发现以下异常:

{amqp_error,precondition_failed,"unknown delivery tag 1",'basic.ack'}
  ...
  {amqp_error,precondition_failed,"unknown delivery tag 1",'basic.ack'}
  ...
  {amqp_error,precondition_failed,"unknown delivery tag 1",'basic.ack'}
  ...

提示未知的 delivery tag=1,该字段为MQ server 用于消息确认的标记,服务端因无法识别而打印错误。

另外一个现象则是,连续收发消息 5次,其中丢失消息处理1次,而 rabbitmq server错误日志出现 4次!

经过分析,发现问题原因所在:

rabbitmq 为每一个channel维护了一个delivery tag的计数器,这里采用正向自增,新消息投递时自增,当消息响应时自减;

在连续收发的场景中,由于消息发送的间隔较短,部分消息因 consumer的重复确认被rabbitmq 当做已处理而丢弃。

解决方案

取消consumer 的自动应答机制,仅保留手动应答的处理,问题解决。

关于 rabbitmq 消息确认机制


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
消息中间件 数据库
RabbitMQ消息的重复消费问题如何解决的
RabbitMQ消息的重复消费问题如何解决的
1651 0
|
消息中间件 存储 缓存
RabbitMq如何防止消息被重复消费
RabbitMq如何防止消息被重复消费
1332 0
|
消息中间件 NoSQL Java
【RabbitMQ】RabbitMQ如何做到保证消息100%不丢失?
【RabbitMQ】RabbitMQ如何做到保证消息100%不丢失?
446 0
|
3月前
|
消息中间件 Java 开发者
如何避免RabbitMQ消息丢失?
本文探讨了RabbitMQ中如何避免消息丢失的问题。在默认情况下,RabbitMQ并不保证消息的持久性,但提供了多种机制来确保消息的可靠传输与处理。文章分析了消息可能丢失的关键环节,并介绍了相应的保证机制:发布者确认交换机已接收消息、确认队列接收消息、队列及消息的持久化,以及消费者成功处理消息后的确认。通过Java代码示例展示了如何在实际应用中实现这些机制。最终,确保了消息在从生产到消费的整个流程中的可靠性。
|
6月前
|
消息中间件 存储 程序员
RabbitMQ消息丢失的场景,如何保证消息不丢失?(详细讲解,一文看懂)
RabbitMQ消息丢失的场景,如何保证消息不丢失?(详细讲解,一文看懂)
325 0
RabbitMQ消息丢失的场景,如何保证消息不丢失?(详细讲解,一文看懂)
|
6月前
|
消息中间件 存储 程序员
四、RabbitMQ如何保证消息丢失
四、RabbitMQ如何保证消息丢失
66 0
|
消息中间件 存储 运维
优雅地处理RabbitMQ中的消息丢失
优雅地处理RabbitMQ中的消息丢失
|
消息中间件 缓存 中间件
RabbitMQ重复消费的原因
关于RabbitMQ重复消费的原因
983 1
|
Java Spring
RabbitMQ-如何保证消息不丢失
RabbitMQ-如何保证消息不丢失
94 0
|
消息中间件
RabbitMQ消息的重复消费问题如何解决的?
RabbitMQ消息的重复消费问题是在分布式系统中常见的一个挑战,解决该问题可以采取以下几种策略:
752 0