ActiveMQ中断(RuntimeTestEvaluator.visit(ShadowMatchImpl.java:140))

本文描述了一次因MQ中断导致业务流程停滞的紧急故障处理过程。通过对MQ配置、业务代码和Spring框架问题的分析,逐步定位到了问题所在,并最终通过代码优化解决了问题。

场景描述

       临下班时,突然接到电话。说某个客户的生产环境上,MQ中断,不能再接收数据,导致整个业务流程中断。由于临下班本来就是一个业务操作的高峰期,造成大面积的客户,门店等待。

       通过了解情况,客户环境通过MQ进行消息中转,解决核心业务系统与我方系统的解藕。我方系统为四个tomcat的集群。

       查看MQ的console,消息量一直在持续增加,其他的消息目标仍有消费者。由此推出MQ服务器本身应该没有问题。

       根据前方的同事的反馈,重启业务系统,MQ上仍然没有消费者。同时反馈中,数据库上有死锁。日志上有标题上的空指针异常。详细如下:

 

java.lang.NullPointerException
	at org.aspectj.weaver.reflect.ShadowMatchImpl$RuntimeTestEvaluator.visit(ShadowMatchImpl.java:140)
	at org.aspectj.weaver.ast.Instanceof.accept(Instanceof.java:29)
	at org.aspectj.weaver.reflect.ShadowMatchImpl$RuntimeTestEvaluator.matches(ShadowMatchImpl.java:121)
	at org.aspectj.weaver.reflect.ShadowMatchImpl.matchesJoinPoint(ShadowMatchImpl.java:78)
	at org.springframework.aop.aspectj.AspectJExpressionPointcut.matches(AspectJExpressionPointcut.java:313)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:159)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
	at $Proxy24.save(Unknown Source)

 

 

        于是乎,怀疑解决死锁是因为有四台同时接收MQ消息。于是关掉三台业务系统的MQ接收,同时在去掉死锁后,重启业务系统,发布可以正常接收MQ消息了。虽然不能理解数据库的死锁跟MQ的中断有什么关系。同时,日志中的NullpointException又有什么关系?

         正当高兴问题已经解决时,前方又反馈MQ上对应的消费者又丢失了。

         于是按日志上的NullpointException去google了一下。这个明显是spring内部的问题,会跟数据有关系吗?

         打到以下bug记录(https://bugs.eclipse.org/bugs/show_bug.cgi?id=318899)。即在spring2.5对应的切面实现中,aspectj对函数第一个参数为空值的情况有bug。会抛出上面提到的异常。顺势查找接口代码,对于外部消息的主键查找本地记录时,没有判断是否存在,都进行save操作。添加判断后,此问题解决。

 

还原错误过程

        一、首先系统MQ接收接口编写不严谨。

                1、没有使用连接池(PooledConnectionFactory)。这样,接收过程由于网络或其他原因中断连接后,不能再重新连接MQ服务器,建立消费者关系。

                2、消息接收自动AUTO_ACK模式,于是接收过程有异常情况,不能正常处理消息的情况下。MQ服务器的消息已经被接收下来并自动给予了ACK回执。有可能造成消息丢失。

        

        二,业务接收代码编写不严谨,没有进行合理的判断。

        

         三,为什么在MQ上的消费者会消失?

               虽然在onMessage里,代码有进行try catch异常。但因为数据问题及程序没有合理判断,同时spring中AspectJ的bug。应该是由于NullException进而引发Error抛出,不能被拦截。所有连接失效。

 

         四,为什么重启,有时候有效有时候无效?

                因为前面提到的编写不严谨,消息一接收就从MQ上进行删除。所有一条错误数据的消息接收一次就消失了,刚好下一条消息是正常的,则重启成功了。如果下一条消息也是错误,不存在的数据,那么tomcat重启后,实际是有建立MQ的消费者的,只是一接收马上又挂了。等我们去console查看时,早已显示无MQ消费者接收了。

 

         五,假设第一条MQ编写严谨,而第二点依然没有进行业务判断,结果如何?

           原系统中,存在一定的将错就错。如果只修改第一条,而第二条不改的话,将造成无限死循环。因为错误结果的消息一直收不到ACK,就直存在于MQ服务器中。

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2025-09-03 10:38:09.880 [main] ERROR org.springframework.boot.SpringApplication:860 - Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'activeMQConfig': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.activemq.user' in value "${spring.activemq.user}" at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:405) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1318) at com.hopedove.bsd.bas.BASApplication.main(BASApplication.java:19) Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.activemq.user' in value "${spring.activemq.user}" at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210) at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175) at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:936) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1321) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ... 18 common frames omitted 2025-09-03 10:38:09.884 [Thread-2] WARN com.alibaba.nacos.common.http.HttpClientBeanHolder:108 - [HttpClientBeanHolder] Start destroying common HttpClient 2025-09-03 10:38:09.886 [Thread-2] WARN com.alibaba.nacos.common.http.HttpClientBeanHolder:114 - [HttpClientBeanHolder] Destruction of the end
最新发布
09-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值