线上RocktMQ重复投递半事务消息故障排查
1. 故障现象
2020-11-18 10:40开始,业务线反馈线上收到大量的重复MQ半事务消息,导致容器资源消耗急剧攀升,经查看MQ日志,发现broker-b的Master服务,报出大量半事务消息回查日志,且每次回查的起始offset不变化,但opOffset不断迅速增大,且HALF_TOPIC队列急速膨胀,查看RocketMQ console监控web后台,发现出现大量消息堆积,且都在broker-B。offset日志如下:


2. 原因分析
2.1. MQ半事务消息回查机制
1、producer提交半事务消息,会先存储在RMQ_SYS_TRANS_HALF_TOPIC队列(以下简称HALF队列)
2、如果producer在MQ回查前,主动确认了本次事务结果,不管是提交还是回滚,MQ都会把该消息转存至RMQ_SYS_TRANS_OP_HALF_TOPIC队列(以下简称OP队列),且如果事务是成功提交的,同时把消息转存至真实的topic,让消费者进行消费。
3、如果producer未能及时确认事务结果,则MQ会定时消费HALF队列,回查对应事务的结果,根据回查结果进行跟上述第二点一样的处理。
4、如果当前事务消息尚未超时,则本次回查终止。
5、更新HALF队列的消费进度offset,等待下一次定时回查,从最新进度offset开始。
2.2. 故障原因
1、MQ默认对超出4K的消息进行压缩存储,并设置sysFlag为已压缩

2、半事务消息需要回查时,从HALF获取消息,如果消息是被压缩过的,此处会进行解压处理


3、把解压后的消息renew一份,追加到HALF队列后,sysFlag标记仍为已压缩,但实际msgBody已经解压

4、下次回查时,该事务消息仍未有结果,对其进行回查,但将其从HALF里读出时出现异常,因为根据sysFlag,消息进行了压缩,但实际进行解压又失败

5、NPE异常未被捕获,直接抛到TransactionalMessageServiceImpl.check()方法,该方法仅打印出来,未作其他业务处理,导致未能更新HALF的回查offset,导致下次回查,仍然从上次的offset开始,陷入死循环


3. 解决方案
1、临时解决方案:
- a)故障当天通过手动修改HALF的offset,让其跳过异常消息,得以恢复。
- b)可以暂时修改transactionTimeout参数,加大半事务消息的事务超时时间,降低MQ回查的概率,规避出现故障。
- c)可以暂时修改Producer端的compressMsgBodyOverHowmuch参数,加大启用压缩的阈值(不推荐)。
2、最终解决方案:
MQ官方4.6.0+以后的版本已经修复该问题,对新版MQ进行稳定性测试后,升级到生产。
线上RocktMQ重复投递半事务消息故障排查的更多相关文章
- 线上CPU100%?看看这篇是怎么排查的!
前言 作为后端开发工程师,当收到线上服务器CPU负载过高告警时,你会这么做?重启服务,忽略告警?不过在我看来一个合格的工程师是一定要定位到具体问题所在的,从而 fix 它.下面记录一下线上服务器 CP ...
- JVM 常见线上问题 → CPU 100%、内存泄露 问题排查
开心一刻 明明是个小 bug,但就是死活修不好,我特么心态崩了...... 前言 后文会从 Windows.Linux 两个系统来做示例展示,有人会有疑问了:为什么要说 Windows 版的 ? 目前 ...
- 记一次线上环境 ES 主分片为分配故障
故障前提 ElasticSearch 版本:5.2 集群节点数:5 索引主分片数:5 索引分片副本数:1 线上环境ES存储的数据量很大,当天由于存储故障,导致一时间 5个节点的 ES 集群,同时有两个 ...
- RocketMQ事务消息实现分析
这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...
- 线上问题排查神器 Arthas
线上问题排查神器 Arthas 之前介绍过 BTrace,线上问题排查神器 BTrace 的使用,也说它是线上问题排查神器.都是神器,但今天这个也很厉害,是不是更厉害不好说,但是使用起来非常简单.如果 ...
- 一个SQL注释引发的线上问题
最近开始服务拆分,时间将近半个月.测试阶段也非常顺利,没有什么问题. 但上线之后的第二天,产品就风风火火的来找我们了,一看就是线上有什么问题.我们也不敢说,我们也不敢问,线上的后台商品忽然无法上架了, ...
- MySQL死锁系列-线上死锁问题排查思路
前言 MySQL 死锁异常是我们经常会遇到的线上异常类别,一旦线上业务日间复杂,各种业务操作之间往往会产生锁冲突,有些会导致死锁异常.这种死锁异常一般要在特定时间特定数据和特定业务操作才会复现,并且分 ...
- [svc]线上Iptables重启报错
线上iptables重启了下发现报错,排查了下 [root@xxxx ~]# /etc/init.d/iptables restart iptables: Setting chains to poli ...
- 分布式开放消息系统RocketMQ的原理与实践(消息的顺序问题、重复问题、可靠消息/事务消息)
备注:1.如果您此前未接触过RocketMQ,请先阅读附录部分,以便了解RocketMQ的整体架构和相关术语2.文中的MQServer与Broker表示同一概念 分布式消息系统作为实现分布式系统可扩展 ...
- RocketMQ(消息重发、重复消费、事务、消息模式)
分布式开放消息系统(RocketMQ)的原理与实践 RocketMQ基础:https://github.com/apache/rocketmq/tree/rocketmq-all-4.5.1/docs ...
随机推荐
- vim 从嫌弃到依赖(12)——打开及保存文件
在前几篇文章中,我们从vim各种模式的使用着手介绍了vim如何进行文本本身的编辑.也通过缓冲区列表的介绍了解到了vim是如何进行打开文件的管理.这篇我们将会着眼于文件的打开和保存的基本操作.通过这篇的 ...
- 6.7 Windows驱动开发:内核枚举LoadImage映像回调
在笔者之前的文章<内核特征码搜索函数封装>中我们封装实现了特征码定位功能,本章将继续使用该功能,本次我们需要枚举内核LoadImage映像回调,在Win64环境下我们可以设置一个LoadI ...
- 9.3 Windows驱动开发:内核解析PE结构节表
在笔者上一篇文章<内核解析PE结构导出表>介绍了如何解析内存导出表结构,本章将继续延申实现解析PE结构的PE头,PE节表等数据,总体而言内核中解析PE结构与应用层没什么不同,在上一篇文章中 ...
- C/C++ 内存遍历与KMP特征搜索
内存遍历,枚举数据,实现特征码扫描. 内存遍历: 每次读入4096字节,然后每16个字符换一次行,遍历内存 0x00401000 - 0x7FFFFFFF. #include <stdio.h& ...
- 多路io复用Select [补档-2023-07-16]
select 2.1 简介 select函数可以用于实现高效的多路复用 I/O,同时处理多个文件描述符的事件,包括监听可读.可写和异常条件,具有阻塞和非阻塞模式,并可以设置超时时间.这使得程序能够 ...
- Python二分法
二分法 尽管二分搜索通常优于顺序搜索,但当n较小时,排序引起的额外开销可能并不划算.实际上应该始终考虑,为了提高搜索效率,额外排序是否值得.如果排序一次后能够搜索多次,那么排序的开销不值一提.然而,对 ...
- 如何控制Tomcat的catalina.out的大小
catalina.out文件,数据主要来源为:System.out 和 System.err 在控制台上直接输出的信息. 编码时应避免使用System.out.println()和e.printSta ...
- cs50ai2
cs50ai2-------Uncertainty cs50ai2-------Uncertainty 基础知识 课后题目 代码实践 学习链接 总结 基础知识 在这节课中,前面主要介绍了一些概率论的基 ...
- LeetCode组合总和I~IV和背包问题小结
一.组合总和问题 最近在看leetcode的组合问题,一共四道,总结一下共通之处与不同之处. 原题链接: 组合总和 组合总和II 组合总和III 组合总和IV 对比如下,为了便于对比,将原题目的叙述方 ...
- CF1841
A 题意:给一个长度为 \(n\) 的全是 \(1\) 的数列,Alice 先操作,Bob 交替.每次操作选择至少两个(可以更多)相等的数字,删除它们,在序列中加入它们的和.直到有人不能操作为止,这个 ...