RocketMQMessageListener使用错误问题分析与排查

背景

RocketMQ与SpingBoot相结合可以大大降低我们开发的复杂度,但是最近在一个新项目中使用RocketMQMessageListener 监听消息,导致消费者启动失败,提示该消费组已经被创建了,请重新申请一个消费者组。

Caused by: org.apache.rocketmq.client.exception.MQClientException: The consumer group[pomp_pstConsumerGroup] has been created before, specify another name please.

于是更换了一个消费者组,依然提示上面的错误。

问题分析

代码中没有看出有什么异常之处,在Nacos中预制了一个开关,然后控制消费逻辑。

@RocketMQMessageListener(consumerGroup = "pomp_pstConsumerGroup",topic = "pts-topic")
@Component
@RefreshScope
public class PtsAuditConsumer implements RocketMQListener<PtsAuditEvent> {@Value("${mq.swtich:false}")private boolean isStop;@Overridepublic void onMessage(PtsAuditEvent event) {if(isStop){return;}// 省略业务代码}
}

我们在RocketMQ 消费者启动代码中发现,是在DefaultMQPushConsumerImpl类中525行报错,原因是在

第521行注册消费者的时候注册失败了。

image-20230910080955419

于是在registerConsumer中我们看到在执行putIfAbsent的时候出错了,说明消费者组与消费者是一一对应的,导致注册失败了。

image-20230910080857231

但是我在项目中检查,该消费者组与消费者并没有重复出现,那么Spring为什么会提示重复呢?既然提示消费者重复,那么我们在启动消费者的时候指定instanceName名,继承RocketMQPushConsumerLifecycleListener,随机生产一个uuid作为instanceName,这样确保Consumer不会重复。

    @Overridepublic void prepareStart(DefaultMQPushConsumer defaultMQPushConsumer) {defaultMQPushConsumer.setInstanceName(UUIDUtil.getUUID32());}

此时消费者已经启动了,但是我们在RocketMQ的控制台可以看到,该topic下有四个queue,有两个consumerClient均分4个queue。此时又开始疑惑了,命名只启动了一个消费者,为什么会有两个consumerClinet呢?这也就是为什么不指定InstanceName时消费者组重复的根本原因。

image-20230910082429278

于是开始推测,是什么原因导致Spring在启动的时候,该Bean在被创建了两次?最后我们从RocketMQMessageListener加载的代码开始分析问题。

image-20230910085018281

果然在ListenerContainerConfiguration中获取RocketMQMessageListener注解的所有实例,获取到两个,这两个消费者是指向同一个类,其中一个的bean是以scopedTarget开头,那么我们就要寻找在什么地方将beanName代理成了scopedTarget.beanName。

image-20230910092637263

在最终debug下我们发现在ScopedProxyUtils中会将加了@RefreshScope注解的类重新代理了,这就导致我们在注入RocketMQ在启动消费者的时候加载了两次。所有我们最终得出结论,RocketMQMessageListener与RefreshScope注解不能同时使用,可以将RefreshScope作为一个Configuration注入到消费者即可。

思考

1、使用了@RefreshScope + 指定instanceName的方式启动消费者有什么问题?

由于指定了instanceName导致服务中存在两个消费者,如果在Nacos中刷新了配置,则有一个消费者能监听到配置更新,另一个消费者无法监听到配置更新;另一方面频繁的更新配置会触发消费者reblance机制,使得消费性能下降。

2、如果使用了Apollo作为配置中心,是否存在这个问题呢?

Apollo不依赖于RefreshScope 的作用域,所有不加RefreshScope 注解,Apollo也可正常启动,不受影响。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】 Python 和 NumPy 系列教程(三):Python容器:1、列表List详解(初始化、索引、切片、更新、删除、常用函数、拆包、遍历)

目录 一、前言 二、实验环境 三、Python容器&#xff08;Containers&#xff09; 0、容器介绍 1、列表&#xff08;List&#xff09; 1. 初始化 a. 创建空列表 b. 使用现有元素初始化列表 c. 使用列表生成式 d. 复制列表 2. 索引和切片 a. 索引 b. 负数索引 c. 切…

龙迅LT86102UX HDMI一进二出,支持分辨率4K60HZ

龙迅LT86102UXE 1. 描述 龙迅LT86102UX HDMI2.0 分路器具有符合 HDMI2.0/1.4 规范的 1&#xff1a;2 分路器、最大 6Gbps 高速数据速率、自适应均衡 RX 输入和预强调的 TX 输出&#xff0c;支持长电缆应用&#xff0c;板载无 XTAL&#xff0c;可节省 BOM 成本。 LT86102UX HDM…

【Linux】- Linux下搭建Java环境[IDEA,JDK8,Tomcat]

Java环境 1. 安装JDK2.安装tomcat3.安装idea4. 安装MySQL5.7 1. 安装JDK /usr/local&#xff1a;存放用户自行安装的软件&#xff0c;默认情况下不会被系统软件包管理器管理 发现解压后的文件已经整体移动到/usr/local/java 文件夹下 打开bin目录&#xff0c;可以看到java的版…

Nginx参数配置详细说明【全局、http块、server块、events块】【已亲测】

Nginx重点参数配置说明 本文包含Nginx参数配置说明全局块、http块、server块、events块共计30多个参数配置与解释&#xff0c;其中常见参数包含配置错误出现的错误日志&#xff0c;能让你更快的解决问题。 该文的所有参数大部分经过单独测试&#xff0c;错误都是自己收集出来的…

每日刷题-3

目录 一、选择题 二、编程题 1、计算糖果 2、进制转换 一、选择题 1、 解析&#xff1a;在C语言中&#xff0c;以0开头的整数常量是八进制的&#xff0c;而不是十进制的。所以&#xff0c;0123的八进制表示相当于83的十进制表示&#xff0c;而123的十进制表示不变。printf函数…

(翻译)JavaFX高级教程:JavaFX2.0的FXML语言

原文地址http://download.oracle.com/javafx/2.0/fxml_get_started/jfxpub-fxml_get_started.htm FXML是JavaFX 2.0新引入的。你可能会问"What is FXML?" 和"Is FXML for me?" FXML 是基于XML的一种声明性标记语言&#xff0c;用来定义应用的用户接口。F…

QT设计一个小闹钟

设置一个闹钟&#xff0c;左侧窗口显示当前时间&#xff0c;右侧设置时间&#xff0c;以及控制闹钟的开关&#xff0c;下方显示闹钟响时的提示语。当按启动按钮时&#xff0c;设置时间与闹钟提示语均不可再改变。当点击停止时&#xff0c;关闭闹钟并重新启用设置时间与闹钟提示…

【MySQL】详解聚合查询、多表查询

MySQL 增删查改&#xff08;进阶&#xff09; 文章目录 MySQL 增删查改&#xff08;进阶&#xff09;01 表的设计表的三大范式 02 查询操作进阶新增聚合查询countsumavgmaxmin 分组查询 GROUP BYHAVING 联合查询/多表查询关键思路引入内连接外连接左外连接&#xff1a;left joi…

有限状态机的概念

一、有限状态机的概念 有限状态机简称状态机&#xff0c;是表示有限个状态&#xff0c;以及在状态之间的转移和动作等行为的数学模型。状态机的要素有状态和状态转移两个。 在Unity中&#xff0c;动画状态机最重要的属性就是节点和连线&#xff0c;其中每个节点都是一个动画片…

Emscripten安装并配置环境变量

前言 Emscripten官网 官网有安装教程&#xff0c;但有些细节没有讲清楚&#xff0c;本文会很详细的讲解每一步。 一、下载 emsdk 包 emsdk – github地址 可以使用 git 去拉取&#xff0c;不过可能会超时拉取失败。 git clone https://github.com/emscripten-core/emsdk.…

数据结构与算法-队列

一.队列的基本概述 1.队列的定义 答&#xff1a;队列是现在在两端进行插入和删除操作的线性表&#xff0c;"队尾"是允许进行存入…

系统软件启动过程

实验一&#xff1a;系统软件启动过程 参考 重要文件 调用顺序 1. boot/bootasm.S | bootasm.asm&#xff08;修改了名字&#xff0c;以便于彩色显示&#xff09;a. 开启A20 16位地址线 实现 20位地址访问 芯片版本兼容通过写 键盘控制器8042 的 64h端口 与 60h端口。b.…

ApachePulsar原理解析与应用实践(学习笔记一)

随着时代的发展&#xff0c;软件设计的理念也在不断发展&#xff0c;从单体服务、面向服务、微服务&#xff0c;发展到云原生以及无服务。其演变的过程是一个能力不断增强&#xff0c;领域边界不断微分细化的过程。比如无服务就是将函数作为服务&#xff0c;就类似dns模式的服务…

什么是50ETF期权开户条件,怎么开期权交易权限?

50ETF期权是指上证50ETF期权&#xff0c;标的物是上证50ETF&#xff0c;代码是&#xff08;510500&#xff09;&#xff0c;期权是一种在上证50ETF基础上进行衍生品交易的金融工具&#xff0c;下文科普什么是50ETF期权开户条件&#xff0c;怎么开期权交易权限&#xff1f;本文来…

死锁

目录 什么是死锁 产生的条件 死锁避免 银行家算法 问题引入 银行家算法的实现思想 死锁检测 每种类型一个资源的死锁检测 每种类型多个资源的死锁检测 死锁恢复 鸵鸟算法 什么是死锁 线程死锁是指由于两个或者多个线程互相持有对方所需要的资源&#xff0c;导致这些线…

3.3.2 【MySQL】客户端和服务器通信中的字符集

3.3.2.1 编码和解码使用的字符集不一致的后果 我们知道字符 我 在 utf8 字符集编码下的字节串长这样&#xff1a; 0xE68891 &#xff0c;如果一个程序把这个字节串发送到另一个程序里&#xff0c;另一个程序用不同的字符集去解码这个字节串&#xff0c;假设使用的是 gbk 字符集…

3ds max插件CG MAGIC中的室外功能可以高效出图吗?

使用3ds Max高效出图秘诀有没有什么秘诀呢&#xff1f;如何做到快速出图呢&#xff1f; 3ds max插件CG MAGIC中的室外功能可以高效出图吗&#xff1f; CG MAGIC 是一款基于3DS max深入开发的智能辅助设计插件。 自从CG Magic专业版上线之后&#xff0c;小伙伴们对新功能诀窍…

Java中如何进行加锁??

笔者在上篇文章介绍了线程安全的问题&#xff0c;接下来本篇文章就是来讲解如何避免线程安全问题~~ 前言&#xff1a;创建两个线程&#xff0c;每个线程都实现对同一个变量count各自自增5W次&#xff0c;我们来看一下代码&#xff1a; class Counter{private int count0;publi…

数学的魅力

数学的魅力 数学的历史古代数学古希腊数学中世纪数学文艺复兴数学 数学的分支1. 代数学2. 几何学3. 微积分学4. 概率论与统计学5. 数论 数学的重要性1. 科学和技术2. 经济学和金融3. 医学和生物学4. 社会科学5. 环境科学 数学的未来1. 人工智能2. 网络安全3. 空间探索 结论 数学…

docker-compose安装nginx

基于docker-compose安装nginx 目录 一、目录结构 1、docker-compose.yml 2、nginx.conf 3、default.conf 4、index.html 二、访问测试 一、目录结构 1、docker-compose.yml version: 3 services:nginx:image: registry.cn-hangzhou.aliyuncs.com/zhengqing/nginx:1.21.1…