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

简介: 生产环境一个问题让我直接“懵”了

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

ffbc343b094a29ec0dd6847c8223d31e.png

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


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

60e308c9933336611027dfd3de781ea4.png

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


那个时候服务集群并没有发现什么异常,消费者没有重启、队列也没发生重平衡,不符合RocketMQ会重复推送消息给客户端的场景,那基本就可以断定是消息消费失败重启引起的,但RocketMQ消息消费重试重试延迟是采取间隔的,往往第一次重试只需10秒就会发生重试,不应该是10个小时?


为此,我特意根据Key分别查找了主题SCHEDULE_TOPIC_XXXX与%RETRY%重试主题,发现这个key也只有一条消息,说明这还仅仅是第一次重试,如下图:

31dc2f96b9f4332d22268858f940e433.png

7d46f245be1d7eef4a6432fe8ef47550.png

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


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


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


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

dccad54daa08437c2bd9d56271a34ed4.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会失败呢?这次比较遗憾,因为项目组使用的是容器,这块代码并没有采集到日志集群,导致无法查看错误日志,而且所在的集群是正常的

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
7月前
|
Dubbo Java 应用服务中间件
项目中引进这玩意,排查日志又快又准
随着微服务盛行,很多公司都把系统按照业务边界拆成了很多微服务,在排错查日志的时候,因为业务链路贯穿着很多微服务节点,导致定位某个请求的日志以及上下游业务的日志会变得有些困难。
|
10月前
|
运维 Java 关系型数据库
spug上线服务踩坑记
spug是一款优秀的自动化运维平台, 这让我们想自动化又向前迈了一步.
357 0
|
11月前
|
存储 人工智能
【一】曾经那些错误,你又踩坑了吗?(一)
【一】曾经那些错误,你又踩坑了吗?
41 0
|
11月前
|
存储 编译器 C++
【一】曾经那些错误,你又踩坑了吗?(二)
【一】曾经那些错误,你又踩坑了吗?
59 0
|
运维 NoSQL Redis
运维和开发慌了,Redis突然 "慢" 了,到底谁背锅?
运维和开发慌了,Redis突然 "慢" 了,到底谁背锅?
|
存储 消息中间件 缓存
做这么多年程序员了,才把ELK和springboot的日志解决方案弄明白
日志监控方案 日志对我们进行系统故障定位具有关键的作用。我们的框架代码、系统环境及业务逻辑中一般都会产出一些日志,我们通常会把这些日志记录后统一收集起来,方便在需要的时候进行查询检索。ELK是目前开源领域比较流行且成熟的一站式日志解决方案。
|
Java 数据库
以为很熟悉CountDownLatch的使用了,没想到在生产环境翻车了
我们知道用来控制并发流程的同步工具,主要的作用是为了等待多个线程同时完成任务后,在进行主线程任务。
|
测试技术
软件测试面试题:软件上线后有bug怎么处理?
软件测试面试题:软件上线后有bug怎么处理?
169 0
|
测试技术
如何处理不能复现的bug?软件测试工程师避坑指南
软件测试工作中常常会遇到不能复现的bug,遇到这种情况其实很正常,但是很多测试新手都按照自己的想法处理,没有提交bug,或者匆匆关闭bug。线上出现问题,就只能自己背锅了。
330 0
|
Prometheus 监控 Cloud Native
SpringBoot服务监控机制,总算整明白了!
SpringBoot服务监控机制,总算整明白了!
SpringBoot服务监控机制,总算整明白了!