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 消息确认机制:
http://www.rabbitmq.com/confirms.html#when

rabbitmq 重复ACK导致消息丢失的更多相关文章

  1. APNS导致消息丢失和发送效率原因

    http://blog.csdn.net/tlq1988/article/details/9612237 首先说明一下,本文只是介绍一些容易被开发者忽视,而导致性能低下问题.并不是介绍如何向苹果设备成 ...

  2. 解决RabbitMQ消息丢失问题和保证消息可靠性(一)

    原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...

  3. RabbitMQ防止消息丢失

    转载请注明出处 0.目录 RabbitMQ-从基础到实战(1)— Hello RabbitMQ RabbitMQ-从基础到实战(3)— 消息的交换 1.简介 RabbitMQ中,消息丢失可以简单的分为 ...

  4. 如何处理RabbitMQ 消息堆积和消息丢失问题

    消息堆积 解决方案: 增加消费者或后台相关组件的吞吐能力 增加消费的多线程处理 根据不同的业务实现不同的丢弃任务,选择不同的策略淘汰任务 默认情况下,RabbitMQ消费者为单线程串行消费,设置并行消 ...

  5. RabbitMQ 和 Kafka 的消息可靠性对比

    RabbitMQ和Kafka都提供持久的消息保证.两者都提供至少一次和至多一次的保证,另外,Kafka在某些限定情况下可以提供精确的一次(exactly-once)保证. 让我们首先理解一下上述术语的 ...

  6. RabbitMQ-从基础到实战(2)— 防止消息丢失

    转载请注明出处 1.简介 RabbitMQ中,消息丢失可以简单的分为两种:客户端丢失和服务端丢失.针对这两种消息丢失,RabbitMQ都给出了相应的解决方案. 2.防止客户端丢失消息 如图,生产者P向 ...

  7. RabbitMQ实战:理解消息通信

    RabbitMQ是一个开源的消息代理和队列服务器,可以通过基本协议在完全不同的应用之间共享数据,可以将作业排队以便让分布式服务进行处理. 本篇介绍下消息通信,首先介绍基础概念,将这些概念映射到AMQP ...

  8. 【RabbitMQ】如何进行消息可靠投递【上篇】

    说明 前几天,突然发生线上报警,钉钉连发了好几条消息,一看是RabbitMQ相关的消息,心头一紧,难道翻车了? [橙色报警] 应用[xxx]在[08-15 16:36:04]发生[错误日志异常],al ...

  9. RocketMQ消息丢失解决方案:同步刷盘+手动提交

    前言 之前我们一起了解了使用RocketMQ事务消息解决生产者发送消息时消息丢失的问题,但使用了事务消息后消息就一定不会丢失了吗,肯定是不能保证的. 因为虽然我们解决了生产者发送消息时候的消息丢失问题 ...

随机推荐

  1. Spark的Straggler深入学习(1):如何在本地图形监控远程Spark的GC情况——使用java自带的jvisualvm

    一.本文的目的       Straggler是目前研究的热点,Spark中也存在Straggler的问题.GC问题是总所周知的导致Straggler的重要因素之一,为了了解GC导致的Straggle ...

  2. Mac下使用firefoxdriver

    Mac使用Firefox浏览器只需要设置WebDriver driver = new FirefoxDriver(),不需要安装firefoxdriver,前提是你的Firefox被安装在默认的位置. ...

  3. JSP自定义标签

    在JSP网页编程中,我们通常不满足于jstl或其他的框架,我们也可以自己写属于自己专用的标签. 在这里介绍一下表格中展示JavaBean的自定义标签的使用 第一步:写一个父标签,用来显示获取数据 新建 ...

  4. C#窗体无法接受Keydown事件

    问题一描述:当新建一个窗体时,添加KeyDown事件后,会正常处理,但是当添加有控件时,比如Button,TextBox,不会触发窗体的KeyDown事件,也没有调用KeyDown事件的处理程序. 原 ...

  5. spring结合quartz的定时的2种方式

    1. Spring 的org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean类,使用此方法使开发人员对Quar ...

  6. linux /boot 清理

    随着升级 /boot分区会越来越满 导致后续无法升级  原因是因为每次升级有可能升级内核  但是旧的内核没有删除  所以导致/boot一直增大 解决办法就是删除不需要的内核,一下步骤: 查看所有安装的 ...

  7. 第七章 LED 将为我闪烁:控制发光二级管

    在上一章中了解到驱动程序的开发步骤,并一个实列来演示如何开发一个完整的驱动.但这个驱动只是简单的演示了实现步骤.真正的驱动需要与硬件直接进行相互交互.这节完整的演示驱动程序,控制开发板上的4个led灯 ...

  8. jquery CRUD一个元素class属性

    jquery增加,移除,修改一个html标签的class名字 一个标签可以指定多个class 1.         增加一个class: $(".default").addClas ...

  9. Python 程序员经常犯的 10 个错误

    关于PythonPython是一种解释性.面向对象并具有动态语义的高级程序语言.它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得... 关于Python Python是一种解释性.面向对 ...

  10. 问题:https与http有什么区别啊?

    HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议  它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换信息.它使用安全套接字 ...