RocketMQ 主题扩分片后遇到的坑
消息组接到某项目组反馈,topic 在扩容后出现部分队列无法被消费者,导致消息积压,影响线上业务?
考虑到该问题是发送在真实的线上环境,为了避免泄密,本文先在笔者的虚拟机中来重现问题。
@
1、案情回顾
1.1 集群现状
集群信息如下:
例如业务主体名 topic_dw_test_by_order_01 的路由信息如图所示:
当前的消费者信息:
broker 的配置信息如下:
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
brokerIP1=192.168.0.220
brokerIP2-192.168.0.220
namesrvAddr=192.168.0.221:9876;192.168.0.220:9876
storePathRootDir=/opt/application/rocketmq-all-4.5.2-bin-release/store
storePathCommitLog=/opt/application/rocketmq-all-4.5.2-bin-release/store/commitlog
autoCreateTopicEnable=false
autoCreateSubscriptionGroup=false
备注:公司对 topic、消费组进行了严格的管控,项目组需要使用时需要向运维人员申请,故 broker 集群不允许自动创建主题与自动创建消费组。
由于该业务量稳步提升,项目组觉得该主题的队列数太少,不利于增加消费者来提高其消费能力,故向运维人员提出增加队列的需求。
1.2、RocketMQ 在线扩容队列
运维通过公司自研的消息运维平台,直接以指定集群的方式为 topic 扩容,该运维平台底层其实使用了RocketMQ 提供的 updateTopic 命令,其命令说明如下:
从上图可以得知可以通过 -c 命令来指定在集群中所有的 broker 上创建队列,在本例中,将队列数从 4 设置为 8,具体命令如下:
sh ./mqadmin upateTopic -n 192.168.0.220:9876 -c DefaultCluster -t topic_dw_test_by_order_01 -r 8 -w 8
执行效果如图所示,表示更新成功。
我们再来从 rocketmq-console 中来看命令执行后的效果:
从上图可以得知,主题的队列数已经扩容到了8个,并且在集群的两台broker上都创建了队列。
1.3 消息发送
从 RocketMQ 系列可知,RocketMQ 是支持在线 topic 在线扩容机制的,故无需重启 消息发送者、消息消费者,随着时间的推移,我们可以查看topic的所有队列都参与到了消息的负载中,如图所示:
我们可以清晰的看到,所有的16个队列(每个 broker 8个队列)都参与到了消息发送的,运维小哥愉快的完成了topic的扩容。
2、问题暴露
该 topic 被 5个消费组所订阅,突然接到通知,其中有两个消费组反馈,部分队列的消息没有被消费,导致下游系统并没有及时处理。
3、问题分析
当时到项目组提交到消息组时,我第一反应是先看消费者的队列,打开该主题的消费情况,如图所示:
发现队列数并没有积压,备注(由于生产是4主4从,每一个 broker上8个队列,故总共32个队列),当时由于比较急,并没有第一时间发现这个界面,竟然只包含一个消费者,觉得并没有消息积压,又由于同一个集群,其他消费组没有问题,只有两个消费组有问题,怀疑是应用的问题,就采取了重启,打印线程栈等方法。
事后诸葛亮:其实这完成是错误的,为什么这样说呢?因为项目组(业务方)已经告知一部分业务未处理,说明肯定有队列的消息积压,当根据自己的知识,结合看到的监控页面做出的判断与业务方反馈的出现冲突时,一定是自己的判断出了问题。
正在我们“如火如荼”的认定是项目有问题时,团队的另一成员提出了自己的观点,原来在得到业务方反馈时,他得知同一个主题,被5个消费组订阅,只有其中两个有问题,那他通过rocketmq-console来找两者的区别,找到区别,找到规律,就离解决问题的路近了。
他通过对比发现,出问题的消费组只有两个客户端在消费(通常生产环境是4节点消费),而没有出现问题的发现有4个进程都在处理,即发现现象:出错的消费组,并没有全员参与到消费。正如上面的图所示:只有其中一个进程在处理8个队列,另外8个队列并没有在消费。
那现在就是要分析为啥topic共有16个队列,但这里只有1个消费者队列在消费,另外一个消费者不作为?
首先根据RocketMQ 消息队列负载机制,2个消费者,只有1个消费者在消费,并且一个有一个明显的特点是,只有broker-a上的队列在消费,broker-b上的队列一个也没消费。
正在思考为啥会出现这种现象时,他又在思考是不是集群是不是broker-b(对应我们生产环境是broker-c、broker-d上的队列都未消费)是新扩容的机器?扩容的时候是不是没有把订阅关系在新的集群上创建?提出了疑问,接下来肖工就开始验证猜想,通过查阅broker-c、broker-d在我们系统中创建的时间是2018-4月的时候,就基本得出结论,扩容时并没有在新集群上创建订阅消息,故无法消费消息。
于是运维小哥使用运维工具创建订阅组,创建方法如图所示:
创建好消费组后,再去查看topic的消费情况时,另外一个消费组也开始处理消息了,如下图所示:
4、问题复盘
潜在原因:DefaultCluster 集群进行过一次集群扩容,从原来的一台消息服务器( broker-a )额外增加一台broker服务器( broker-b ),但扩容的时候并没有把原先的存在于 broker-a 上的主题、消费组扩容到 broker-b 服务器。
触发原因:接到项目组的扩容需求,将集群队列数从4个扩容到8个,这样该topic就在集群的a、b都会存在8个队列,但Broker不允许自动创建消费组(订阅关系),消费者无法从broker-b上队列上拉取消息,导致在broker-b队列上的消息堆积,无法被消费。
解决办法:运维通过命令,在broker-b上创建对应的订阅消息,问题解决。
经验教训:集群扩容时,需要同步在集群上的topic.json、subscriptionGroup.json文件。
RocketMQ 理论基础,消费者向 Broker 发起消息拉取请求时,如果broker上并没有存在该消费组的订阅消息时,如果不允许自动创建(autoCreateSubscriptionGroup 设置为 false),默认为true,则不会返回消息给客户端,其代码如下:
问题解决后,我们团队的成员也分享了一下他在本次排查问题的处理方法:寻找出现问题的规律、推断问题、 然后验证问题。规律可以是问题本身的规律 也可以是和正常对比的差。
如果觉得文章写的还不错的话,麻烦帮忙点个赞,谢谢。
作者介绍:丁威,《RocketMQ技术内幕》作者,RocketMQ 社区布道师,公众号:中间件兴趣圈 维护者,目前已陆续发表源码分析Java集合、Java 并发包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源码专栏。可以点击链接加入中间件知识星球 ,一起探讨高并发、分布式服务架构,交流源码。
RocketMQ 主题扩分片后遇到的坑的更多相关文章
- 升级10.11.6后CocoaPods的坑,之前10.11.4已经安装好的,居然没了Failed to locate Homebrew!
升级10.11.6后CocoaPods的坑,之前10.11.4已经安装好的,居然没了,用命令 sudo gem install cocoapod 装不上,换 sudo gem install -n/u ...
- MyEclipse导入主题文件epf后xml及jsp等页面中点击标签之后显示灰白
MyEclipse导入主题文件epf后xml及jsp等页面中点击标签之后显示灰白,症状例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVVAxOT ...
- swiper4自动轮播切换手动触碰后停止踩坑——属性disableOnInteraction
swiper4轮播设置autoplay自动切换后,即默认设置: <script> var mySwiper = new Swiper('.swiper-container', { auto ...
- Mysql分片后分页排序拉取数据的方法
高并发大流量的互联网架构,一般通过服务层来访问数据库,随着数据量的增大,数据库需要进行水平切分,分库后将数据分布到不同的数据库实例(甚至物理机器)上,以达到降低数据量,增加实例数的扩容目的. 一旦涉及 ...
- WordPress 在Ubuntu下安装插件、主题输入FTP后无法创建目录
最近自己在搞基于lnmp+wordpress的个人博客, 一切都就绪后,想改变下自己的主题,然后去Wordpress里面内置的主题安装下载的时候,提示:无法创建目录! 一般我们在Ubuntu系统上面安 ...
- Vue-loader 开启压缩后的一些坑
在使用vue-loader 配合webpack 对.vue文件进行加载的时候,如果开启了代码压缩会出来下面几种问题,做个记录. 丢失td结束标记,导致页面的布局错乱 input的属性type为text ...
- 我们是80后 golang入坑系统
现在这个系列,已经开始两极分化了. 点赞的认为风格轻松,看着不困.反之,就有人嫌写的罗里吧嗦,上纲上线.所以善意提醒,里面不只是技术语言,还有段子.专心看技术的,千万别点!别怪我没提醒!差点忘说,版权 ...
- vs2012升级vs2017后的一些坑
异常信息:未能加载文件或程序集"System.Web.Helpers... 未能加载文件或程序集"System.Web.Helpers, Version=2.0.0.0, Cult ...
- RocketMQ 顺序消费只消费一次 坑
rocketMq实现顺序消费的原理 produce在发送消息的时候,把消息发到同一个队列(queue)中,消费者注册消息监听器为MessageListenerOrderly,这样就可以保证消费端只有一 ...
随机推荐
- Python类属性与实例属性理解
按理讲,类属性改变,类的实例对象这个属性也应该被改变,但是在python中实际却不是这样 class test(): name = 111 a = test() b = test() a.name = ...
- python手册学习笔记1
笔记1 > http://www.pythondoc.com/pythontutorial3/controlflow.html 参数传递 Python中sys.argv的用法 调用解释器时,脚本 ...
- 你了解MySQL中的多表联合查询吗?
前言: 多表联合查询,其实就是我们MySQL中的join语句,经常会看到有人说join非常影响性能,不建议使用,你知道这是为什么呢?我们究竟可不可以用呢? 测试数据: CREATE TABLE `t2 ...
- CentOS7.6手动编译httpd-2.4.25
手动编译httpd-2.4.25 系统:CentOS7.1810 httpd:2.4.25 编译时报错解决技巧:报什么错,就装这个错误的devel,比如报http2错误,就yum search htt ...
- 《计算机网络 自顶向下方法》 第3章 运输层 Part2
待补充完善 TCP 相关基本点 1.面向连接 两个不同主机上的进程在通过 TCP 进行通信之前,必须先通过三次握手来建立 TCP 连接 2.全双工服务 即,如果一台主机上的进程 A 与另一台主机上的进 ...
- ESP8266 使用AT指令
ESP8266 使用AT指令 问题:串口调试工具输入AT指令没返回结果 分析板子有两种模式 下载模式(默认) 运行模式 解决办法: 方法一:按下板子上的 RST 键位 方法二:使用 [安信可串口调试工 ...
- nyoj 98-成绩转换 (if, else if)
98-成绩转换 内存限制:64MB 时间限制:3000ms 特判: No 通过数:49 提交数:74 难度:1 题目描述: 输入一个百分制的成绩M,将其转换成对应的等级,具体转换规则如下: 90~10 ...
- 目录(cd mkdir rmdir rm pwd ls) 文件(ln touch mv rm cat more head rail) 文件权限(chmod chown chgrp) 文件通配符(* ? [])
记住Linux目录树的结构是一个称职Linux系统管理员的必备素质! 目录漫游cd cd - 目录显示pwd 目录管理 mkdir -p a/b/c/1 parent创建多层目录 -m 700 ...
- 【dp】Arrange the Schedule
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3538 题意:如题. 题解: 假如 一组数据 ...(n1)A.. ...
- 实现websocket 主动消息推送,用laravel+Swoole
近来有个需求:想实现一个可以主动触发消息推送的功能,这个可以实现向模板消息那个,给予所有成员发送自定义消息,而不需要通过客户端发送消息,服务端上message中监听传送的消息进行做相对于的业务逻辑. ...