RocketMQ5.x版本延迟消息被重放问题调查

一、问题

由于目标计划是将集群从4.9.x逐步升级至5.x,故目前先对一些不重要的集群进行升级测试。
但是在4.x的broker陆续升级至5.x的过程中,发现了延迟消息被重放的问题。
具体如下:
在升级时刷新后台监控,发现竟然有写入量:
在这里插入图片描述
即上图(因为当时的问题场景没有截图,所以上图只是提供参考)红框中的生产和消费项并不为0,等启动完毕后,变为0,感觉有些诡异。
之后,查询了该集群的topic情况,这一查竟然发现好多topic出现了堆积的情况。

二、调查

1 堆积情况:
经过调查所有topic,这些topic于几日前已经不进行生产和消费,也就是生产消费完成了。
而发现堆积的topic都是之前消费有失败的,产生了重试消息的,而这些重试消息也是被消费完了的。
而我将4.x的一个broker升级到5.x后,重试的消息完全被重放了,类似如下截图:
在这里插入图片描述
%RETRY%pugc-sofa-delete-video-flush-consumer这个topic在broker-cold-1上的消息量变成了34706,而消费量为17353,堆积量跟消费量相等。

我查看了好几个topic,发现只要有重试消息的,都存在这个情况,也就是重试消息被重写了一遍!

2 日志调查
经过拿其中一个消费者:pugc-sofa-delete-video-flush-consumer进行调查,根据该消费者最后在日志中出现的位置,可以看到:

2023-06-05 15:25:18 ERROR NettyServerNIOSelector_3_2 - RemotingCommand [code=11, language=JAVA, version=395, opaque=166848104, flag(B)=0, remark=null, extFields={queueId=0, maxMsgNums=32, sysFlag=3, suspendTimeoutMillis=15000, commitOffset=17353, topic=%RETRY%pugc-sofa-delete-video-flush-consumer, queueOffset=17353, expressionType=TAG, subVersion=1685949771302, consumerGroup=pugc-sofa-delete-video-flush-consumer}, serializeTypeCurrentRPC=JSON]

commitOffset=17353,该消费者在2023-06-05消费重试消息时,消费偏移量已经达到17353。

这进一步确认了,就是因为我升级5.x导致了重试消息被重写了一遍。

我进一步走查了5.x的broker启动时关于%RETRY%pugc-sofa-delete-video-flush-consumer的日志,如下:

store.log:2023-06-07 09:39:13 INFO main - load /opt/mqcloud/broker-cold-1/data/consumequeue/%RETRY%pugc-sofa-delete-video-flush-consumer/0/00000000000000000000 OK
store.log:2023-06-07 09:39:13 INFO main - load consume queue %RETRY%pugc-sofa-delete-video-flush-consumer-0 OK
store.log:2023-06-07 09:39:14 INFO main - recover current consume queue file over,  /opt/mqcloud/broker-cold-1/data/consumequeue/%RETRY%pugc-sofa-delete-video-flush-consumer/0/00000000000000000000 0 0 0
store.log:2023-06-07 09:39:14 INFO main - recover current consume queue over /opt/mqcloud/broker-cold-1/data/consumequeue/%RETRY%pugc-sofa-delete-video-flush-consumer/0/00000000000000000000 347060

根据最后一条的347060,调查对应代码简化如下:

public void recover() {
    final List<MappedFile> mappedFiles = this.mappedFileQueue.getMappedFiles();
    if (!mappedFiles.isEmpty()) {
        int mappedFileSizeLogics = this.mappedFileSize;
        long mappedFileOffset = 0;
        while (true) {
            for (int i = 0; i < mappedFileSizeLogics; i += CQ_STORE_UNIT_SIZE) {
                long offset = byteBuffer.getLong();
                int size = byteBuffer.getInt();
                long tagsCode = byteBuffer.getLong();
                if (offset >= 0 && size > 0) {
                    mappedFileOffset = i + CQ_STORE_UNIT_SIZE;
                } else {
                    log.info("recover current consume queue file over,  " + mappedFile.getFileName() + " "
                        + offset + " " + size + " " + tagsCode);
                    break;
                }
            }
            if (mappedFileOffset == mappedFileSizeLogics) {
            } else {
                log.info("recover current consume queue over " + mappedFile.getFileName() + " "
                    + (processOffset + mappedFileOffset));
                break;
            }
        }
    }
}

347060代表的是重试队列的物理偏移量,由于consumequeue每个数据单元大小是20个字节,那么消息量为347060/20=17353。

也就是说,在broker初始化恢复数据时,重试队列的数据量还是对的。

而broker启动整个过程包括,创建->初始化->数据恢复->启动,如果数据重复,就很可能出现在启动过程中。

3 走查延迟队列代码
通过上面的调查,基本可以确认,重试队列数据刚加载时是对的,应该是启动后内部的延迟队列进行重新消费导致的。

随即对比5.x和4.x的延迟队列相关代码,至到对比到下面的代码:
在这里插入图片描述
在这里插入图片描述
即5.x的ScheduleMessageService竟然在构造方法中添加了一个持久化的定时任务,而且在start方法中又添加了一个同样的持久化的定时任务

而4.x只有在start时,先执行load(),再执行持久化定时任务。

那么5.x的持久化任务在构造方法中延迟10秒就会执行,如果10秒内,数据还没有加载完成,它执行persist必然会把存在的delayOffset.json覆盖

再start时,执行load,加载的offset就是空的,那就会认为没有消费过,进行数据重放

接着再查看store.log的日志,如下:
在这里插入图片描述
在这里插入图片描述
从2023-06-07 09:39:13启动,至到2023-06-07 09:39:24才刚恢复完数据,那么调用start方法肯定在10秒之后了。

而在测试环境中,broker没多少数据,10秒内肯定已经启动完了,所以没有发现这个问题,而线上环境数据量一般都是上百G,通常启动比较慢。

三、解决

所以定位到问题所在,就好改了,直接把5.x中ScheduleMessageService构造方法中的定时持久化代码移除即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/27403.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于组件化开发思想的微信小程序开发框架

跨端框架的出现为小程序应用的开发带来了巨大的便利性和灵活性。它们提供了统一的开发方式、代码复用的能力&#xff0c;并且与小程序容器技术紧密结合&#xff0c;实现了一次编码、多端运行的目标。开发者可以根据项目需求和团队技术栈选择合适的跨端框架&#xff0c;从而在不…

11 GMM——高斯混合模型

文章目录 11 GMM——高斯混合模型11.1 模型介绍11.2 通过MLE估计参数11.3 EM求解 11 GMM——高斯混合模型 11.1 模型介绍 从几何角度来说&#xff1a; 高斯混合模型表示&#xff1a;加权平均——由多个高斯分布混合叠加而成&#xff0c;如图 公式可以表达为&#xff1a; p…

基于XC7Z100的PCIe采集卡(GMSL FMC采集卡)

GMSL 图像采集卡 特性 ● PCIe Gen2.0 X8 总线&#xff1b; ● 支持V4L2调用&#xff1b; ● 1路CAN接口&#xff1b; ● 6路/12路 GMSL1/2摄像头输入&#xff0c;最高可达8MP&#xff1b; ● 2路可定义相机同步触发输入/输出&#xff1b; 优势 ● 采用PCIe主卡与FMC子…

安卓大作业 书籍列表APP

系列文章 安卓大作业 书籍列表APP 文章目录 系列文章1&#xff0e;背景2&#xff0e;功能3. 源代码获取 1&#xff0e;背景 我做的项目是一个可以查看到书籍列表以及详情效果的内容&#xff0c;主要使用到的技术有Intent数据传递以及数据库存储的应用&#xff0c;其次使用的组…

Qt线程的几种使用方法

目录 引言使用方法重写QThread::run()moveToThreadQRunnable使用QtConcurrent使用 完整代码 引言 多线程不应该是一个复杂而令人生畏的东西&#xff0c;它应该只是程序员的一个工具&#xff0c;不应该是调用者过多记忆相关概念&#xff0c;而应该是被调用方应该尽可能的简化调…

Linux教程——常见Linux发行版本有哪些?

新手往往会被 Linux 众多的发行版本搞得一头雾水&#xff0c;我们首先来解释一下这个问题。 从技术上来说&#xff0c;李纳斯•托瓦兹开发的 Linux 只是一个内核。内核指的是一个提供设备驱动、文件系统、进程管理、网络通信等功能的系统软件&#xff0c;内核并不是一套完整的…

网络安全从业人员2023年后真的会被AI取代吗?

随着ChatGPT的火爆&#xff0c;很多人开始担心网络安全从业人员会被AI取代。如果说网络安全挖洞的话&#xff0c;AI可能真的能取代。但是网络安全不仅仅只是挖洞&#xff0c;所以AI只是能缓解网络安全人员不足的情况&#xff0c;但是是不会取代人类的作用的。 就拿最近很火的C…

【线性代数】

求解线性方程组 右乘向量/矩阵 把左边的矩阵拆成一个个列向量&#xff0c;右边的向量表示对左边列向量组的线性组合。 [ c o l 1 c o l 2 c o l 3 ] [ 3 4 5 ] [ 3 c o l 1 4 c o l 2 5 c o l 3 ] \left[\begin{array}{c} col_{1} & col_{2} & col_{3} \end{array}\…

WPS表格处理

wps表格中公式出来的内容如何转为纯文本 选中公式算出的结果区域&#xff0c;复制&#xff0c;在原区域上右键&#xff0c;选择性粘贴为数值&#xff0c;就转成文本了&#xff0c;当然公式也就消除了。 wps表格如何设置整列公式&#xff1f; 1、先来看看下面这个例子需做出商…

Git、Github、Gitee的区别

⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Git 目录 1、Git2、Gitee3、GitHub 什么是版本管理&#xff1f;   版本管理是管理各个不同的版本&#xff0c;出了问题可以及时回滚。 1、Git Git是一个分布式版本控制系统&#xff0c;用于跟踪和管理代码的变化。它是…

【Ubuntu系统内核更新与卸载】

【Ubuntu系统内核更新与卸载】 1. 前言2. 内核安装2.1 系统更新2.2 官网下载 3. 内核卸载3.1 需求分析3.2 卸载方法 1. 前言 我们在搭建环境时常常遇到内核版本不匹配的问题&#xff0c;需要我们安装新的内核版本&#xff1b;有时又会遇到在安装软件时报错boot空间已满无法安装…

2021年国赛高教杯数学建模B题乙醇偶合制备C4烯烃解题全过程文档及程序

2021年国赛高教杯数学建模 B题 乙醇偶合制备C4烯烃 原题再现 C4 烯烃广泛应用于化工产品及医药的生产&#xff0c;乙醇是生产制备 C4 烯烃的原料。在制备过程中&#xff0c;催化剂组合&#xff08;即&#xff1a;Co 负载量、Co/SiO2 和 HAP 装料比、乙醇浓度的组合&#xff0…

(六)CSharp-CSharp图解教程版-委托

一、委托概述 1、什么是委托 委托和类一样&#xff0c;是一种用户定义类型&#xff08;即是一种类&#xff0c;所以也是一个引用类型&#xff09;。在它们组成的结构方面区别是&#xff0c;类表示的是数据和方法的集合&#xff0c;而委托则持有一个或多个方法。 可以把 deleg…

HNU-操作系统OS-作业1(4-9章)

这份文件是OS_homework_1 by计科2102 wolf 202108010XXX 文档设置了目录,可以通过目录快速跳转至答案部分。 第四章 4.1用以下标志运行程序:./process-run.py -l 5:100,5:100。CPU 利用率(CPU 使用时间的百分比)应该是多少?为什么你知道这一点?利用 -c 标记查看你…

[230604] 听力TPO66汇总·上篇| C1 L1 C2|10:20~12:00

目录​​​​​​​ Science Fiction And Sci-fi-C1 错题分析 C1-3 细节双选题 C1 精听练习 做题笔记 Financial Advice-C2 全对 C2 精听练习 Sleep-L1 错题分析 L1-4 细节题 L1-5 细节双选题 L1 精听练习 做题笔记 词汇&#xff1a;http://t.csdn.cn/Zhuws 两篇对…

Linux进程、用户、权限命令

进程管理命令 进程和程序的区别 1 程序是静态概念&#xff0c;本身作为一种软件资源长期保存&#xff1b;而进程是程序的执行过程&#xff0c;它是动态概念&#xff0c;有一定的生命期&#xff0c;是动态产生和消亡的。 2 程序和进程无一一对应关系。一个进程在活动中可有顺序…

软件测试03:软件工程和软件生命周期

软件测试03&#xff1a;软件工程和软件生命周期 软件危机 软件危机是指落后的软件生产方式无法满足迅速增长的计算机软件需求&#xff0c;从而导致软件开发与维护过程中出现一系列严重问题的现象。 软件工程 基本软件危机对于计算机发展的阻碍&#xff0c;1968年&#xff0…

一分钟学一个 Linux 命令 - tar

前言 大家好&#xff0c;我是 god23bin。今天给大家带来的是 Linux 命令系列&#xff0c;每天只需一分钟&#xff0c;记住一个 Linux 命令不成问题。今天&#xff0c;我们要介绍的是一个常用且强大的命令&#xff1a;tar。 什么是 tar 命令&#xff1f; tar 是 tape archive…

SUSTechPOINTS三维点云标注工具使用

官方地址&#xff1a;SUSTechPOINTS 官方中文教程 相关文章&#xff1a; OpenPCDet安装、使用方式及自定义数据集训练 安装 git clone https://github.com/naurril/SUSTechPOINTS cd SUSTechPOINTS pip install -r requirement.txt wget https://github.com/naurril/SUSTec…

STL——string和vector容器

初识STL **STL的基本概念****vector容器存放内置数据类型****在vector容器中存放自定义数据类型****vector容器嵌套vector容器****string容器——构造函数****string容器——赋值操作****string容器——字符串拼接****string容器——字符串的查找和替换****string容器——字符串…