性能文章>生产环境一个问题让我直接“懵”了>

生产环境一个问题让我直接“懵”了原创

4天前
160901

大家好,我是威哥,《RocketMQ技术内幕》作者、RocketMQ社区首席布道师、中通快递基础架构资深架构师,越努力越幸运,唯有坚持不懈,与大家共勉。


前天发完版本好不容易休息一下,又遇到一个问题,项目组反馈说RocketMQ的一个消费组一条消息,消费了两次,但两者之间的间隔超过了10个小时,现象如下图所示:

BC40F620-DE56-406A-86D9-0513F4BF7D30.png

这是为什么呢?两者之间相差了差不多10个多小时,是不是这条消息重复消费了16次,但从日志中并没有打印出16次消息题,只打印了两条消息,从日志角度来看应该不是重复消费了16次。


本着不轻易相信日志的原则,我觉得应该去RocketMQ服务器上看看这条消息存储的重试次数,从而推断出消息是否消费失败而进行消费重试,正好项目组也提供了消息的Key,根据消息key、发送主题名称去查找消息,只能查询到一条消息:

2AC496C7-77B8-4B6C-A418-380390BD405A.png


说明发送端确实只发送了一条消息。


那个时候服务集群并没有发现什么异常,消费者没有重启、队列也没发生重平衡,不符合RocketMQ会重复推送消息给客户端的场景,那基本就可以断定是消息消费失败重启引起的,但RocketMQ消息消费重试重试延迟是采取间隔的,往往第一次重试只需10秒就会发生重试,不应该是10个小时?
为此,我特意根据Key分别查找了主题SCHEDULE_TOPIC_XXXX与%RETRY%重试主题,发现这个key也只有一条消息,说明这还仅仅是第一次重试,如下图:

3B7416E7-79C4-4C0C-9720-44CCDC2B390C.png

28F5A0E7-8F2B-4188-8FCC-4082276EBFBE.png


但从这里可以看到消息写入到SCHEDULE_TOPIC_XXXX的时间为2022-05-27 22:26:20,然后过了10s就通过调度机制进入到重试主题,并开始被消费,故进行了第一次重试。


扩展机制知识:RocketMQ并发消费的消费者,在客户端消费失败后会向服务端发送ACK,根据重试次数进入到SCHEDULE_TOPIC_XXXX主题不同的队列中,每一个队列代表的延迟时间不一样,经过一定延迟时间后再次调度到消费组的重试主题,被消费者再次消费,实现时间间隔的重试,提高重试成功率。


那为什么第一次消费是12点51分,为什么这么久才进入到Broker的SCHEDULE_TOPIC_XXXX呢?


这个就是问题的关键所在,这个细节我平时也没关注,故接下来得分析这段代码,代码具体定义在ConsumeMessageConcurrentlyService的processConsumeResult方法中。

602085B7-001C-4F6E-BB35-9F2393249116.png


原来,如果客户端消费失败后向Broker发生ACK失败后,会加入到msgBack失败队列中,并重新提交到消费者这边消费,并且这条消息的位点不会提交,因为有关键代码:

consumeRequest.getMsgs().removeAll(msgBackFailed);

long offset = consumeRequest.getProcessQueue().removeMessage(consumeRequest.getMsgs());
if (offset >= 0 && !consumeRequest.getProcessQueue().isDropped()) {
   this.defaultMQPushConsumerImpl.getOffsetStore().updateOffset(consumeRequest.getMessageQueue(), offset, true);
}


RocketMQ消费位点采取最小位点提交,只要消息存在于本地处理队列,位点就不会提交,从而会触发消息积压。但尴尬的是这个主题平时消息量很少,并没有通过积压来发现该问题。


根据现象与代码结合,原因是客户端一直消费失败,但向Broker提交ACK一直失败,直到晚上22:26分才发送成功,从而才触发重新消费。


那现在的关键是为什么会发生ACK会失败呢?这次比较遗憾,因为项目组使用的是容器,这块代码并没有采集到日志集群,导致无法查看错误日志,而且所在的集群是正常的,这个疑问后续等我分析完毕后,再和大家来分享,如果粉丝朋友们遇到过,后者分析过,还请留言。


最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙「中间件兴趣圈」关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。关注公众号:「中间件兴趣圈」,在公众号中回复:「PDF」可获取大量学习资料,回复「专栏」可获取15个主流Java中间件源码分析专栏,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。

请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

RocketMQ 在使用上的一些排坑和优化
前言:RocketMQ 在我们的项目中使用非常广泛,在使用的过程中,也遇到了很多的问题。比如没有多环境的隔离,在多个版本同时开发送测的情况下,互相干扰严重。RocketMQ 的投递可能会失败,导致丢失
给 wireshark 写一个 RocketMQ 协议解析的 lua 插件
前言学习 RocketMQ,需要搞懂两个东西:通信和存储。这里花了一点时间写了一个 RocketMQ 的 wireshark lua 插件,过程挺有意思,写出来记录一下。通过阅读这篇文章,你会了解到下
《吃透 MQ 系列》之核心基础篇
上一篇文章谈到了《吃透系列》的讲解思路:先找到每个技术栈最本质的东西,然后以此为出发点,逐渐延伸出其他核心知识。所以,整个系列侧重于思考力的训练,不仅仅是讲清楚 What,而是更关注 Why 和 How,以帮助大家构建出牢固的知识体系。回到正文,这是技术系列《吃透 MQ》的开篇。
RocketMQ这样做,压测后性能提高30%
详细剖析RocketMQ4.9.1版本的性能优化实践
8 个场景RocketMQ 会发生流量控制,一定要警惕!
大家好,我是君哥。在使用 RocketMQ 的过程中,有时候我们会看到下面的日志:[TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while, period in queue: 206ms, size of queue: 5
Spring Boot 多个定时器冲突排查和优化过程
导语实际开发项目中一定不止一个定时器,很多场景都需要用到,而多个定时器带来的问题 : 就是如何避免多个定时器的互相冲突。 正文使用场景我们的订单服务,一般会有一个待支付订单,而这个待支付订单是有时间限制的,比如阿里巴巴的订单是五天,淘宝订单是一天,拼多多订单是一天,美团订单是15
一次C10K场景下的线上Dubbo问题排查及优化
导语Dubbo 是一款轻量级的开源 Java 服务框架,是众多企业在建设分布式服务架构时的首选。中国工商银行自 2014 年开始探索分布式架构转型工作,基于开源 Dubbo 自主研发了分布式服务平台。Dubbo 框架在提供方消费方数量较小的服务规模下,运行稳定、性能良好。随着银行业务线上化、多样
生产环境一个问题让我直接“懵”了
大家好,我是威哥,《RocketMQ技术内幕》作者、RocketMQ社区首席布道师、中通快递基础架构资深架构师,越努力越幸运,唯有坚持不懈,与大家共勉。前天发完版本好不容易休息一下,又遇到一个问题,项目组反馈说RocketMQ的一个消费组一条消息,消费了两次,但两者之间的间隔超过了10个小时,