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重复投递半事务消息故障排查的更多相关文章

  1. 线上CPU100%?看看这篇是怎么排查的!

    前言 作为后端开发工程师,当收到线上服务器CPU负载过高告警时,你会这么做?重启服务,忽略告警?不过在我看来一个合格的工程师是一定要定位到具体问题所在的,从而 fix 它.下面记录一下线上服务器 CP ...

  2. JVM 常见线上问题 → CPU 100%、内存泄露 问题排查

    开心一刻 明明是个小 bug,但就是死活修不好,我特么心态崩了...... 前言 后文会从 Windows.Linux 两个系统来做示例展示,有人会有疑问了:为什么要说 Windows 版的 ? 目前 ...

  3. 记一次线上环境 ES 主分片为分配故障

    故障前提 ElasticSearch 版本:5.2 集群节点数:5 索引主分片数:5 索引分片副本数:1 线上环境ES存储的数据量很大,当天由于存储故障,导致一时间 5个节点的 ES 集群,同时有两个 ...

  4. RocketMQ事务消息实现分析

    这周RocketMQ发布了4.3.0版本,New Feature中最受关注的一点就是支持了事务消息: 今天花了点时间看了下具体的实现内容,下面是简单的总结. RocketMQ事务消息概要 通过冯嘉发布 ...

  5. 线上问题排查神器 Arthas

    线上问题排查神器 Arthas 之前介绍过 BTrace,线上问题排查神器 BTrace 的使用,也说它是线上问题排查神器.都是神器,但今天这个也很厉害,是不是更厉害不好说,但是使用起来非常简单.如果 ...

  6. 一个SQL注释引发的线上问题

    最近开始服务拆分,时间将近半个月.测试阶段也非常顺利,没有什么问题. 但上线之后的第二天,产品就风风火火的来找我们了,一看就是线上有什么问题.我们也不敢说,我们也不敢问,线上的后台商品忽然无法上架了, ...

  7. MySQL死锁系列-线上死锁问题排查思路

    前言 MySQL 死锁异常是我们经常会遇到的线上异常类别,一旦线上业务日间复杂,各种业务操作之间往往会产生锁冲突,有些会导致死锁异常.这种死锁异常一般要在特定时间特定数据和特定业务操作才会复现,并且分 ...

  8. [svc]线上Iptables重启报错

    线上iptables重启了下发现报错,排查了下 [root@xxxx ~]# /etc/init.d/iptables restart iptables: Setting chains to poli ...

  9. 分布式开放消息系统RocketMQ的原理与实践(消息的顺序问题、重复问题、可靠消息/事务消息)

    备注:1.如果您此前未接触过RocketMQ,请先阅读附录部分,以便了解RocketMQ的整体架构和相关术语2.文中的MQServer与Broker表示同一概念 分布式消息系统作为实现分布式系统可扩展 ...

  10. RocketMQ(消息重发、重复消费、事务、消息模式)

    分布式开放消息系统(RocketMQ)的原理与实践 RocketMQ基础:https://github.com/apache/rocketmq/tree/rocketmq-all-4.5.1/docs ...

随机推荐

  1. SqlSugar新增数据

    1.插入方式 1.1 单条插入实体 //返回插入行数 db.Insertable(insertObj).ExecuteCommand(); //都是参数化实现 //异步: await db.Inser ...

  2. 手撕Udp套接字|实现群聊通信|实现Windows & Linux通信交互

    ​ 专栏和Git地址 操作系统https://blog.csdn.net/yu_cblog/category_12165502.html?spm=1001.2014.3001.5482UdpSocke ...

  3. P2572 [SCOI2010] 序列操作 题解

    题解:序列操作 比较综合的 ds 题,综合了线段树常见的几种操作:维护最大子段和.区间翻转.区间求和.区间覆盖 . 维护子段和常见的我们维护三类东西: 前缀最长连续段.后缀最长连续段.当前区间上的最大 ...

  4. ABC 317 A - G

    ABC 317 A - G 代码去 Atcoder 全部提交搜索 Std_Code 查看代码 懒人专用 A $ p_i $ 升序,找最小的 $ i $ 满足 $ p_i + h \ge x $ 直接枚 ...

  5. 记录一则ADG备库报错ORA-29771的案例

    有客户找到我这边咨询,说他们的一套核心ADG库在业务高峰期报错,因为业务做了读写分离,其备库也实际承担读业务,所以备库故障也会对业务产生影响. 这里也要提醒大家,做读写分离,如果读库出现故障的情况,要 ...

  6. Linux反空闲的设置和关闭

    有一定工作经验的运维人基本都会遇到这样的场景,某个窗口自动断开了,提示超时: [oracle@jystdrac1 ~]$ timed out waiting for input: auto-logou ...

  7. liveness-probe探针和readness-probe

    目录 探针 liveness-probe 存活探针 探针的3种方式 1. exec 2. httpGet 3. tcpSocket readness-probe 就绪探针 1. exec 2. htt ...

  8. Java-将文本(字符串)转化成二进制字符

    今天在测试MySQL的Blob相关类型时,这种一般存放的是二进制文本,所以就想插入二进制文本. package com.aaa.dao; public class aaa { public stati ...

  9. 了解一下基本的tcp代理配置

    我们首先用一个简单例子了解一下基本的tcp代理配置 worker_processes 1; #nginx worker 数量 error_log logs/error.log; #指定错误日志文件路径 ...

  10. Docker 容器逃逸漏洞 (CVE-2020-15257)

    漏洞详情 Docker发布一个容器逃逸漏洞,攻击者利用该漏洞可以实现容器逃逸,提升特权并破坏主机. containerd使用的抽象套接字仅使用UID做验证,即任意UID为0的进程均可访问此API. 当 ...