Jasypt导致的性能问题

237 阅读1分钟

现象:

测试对平台接口进行压测,平均每个接口TPS为700多,无法继续压上去。

排查:

1.服务争抢资源

227启着十几个java进程,还有中间件,mysql,python。如果把这些服务都关掉的话,上1000肯定是没有问题的。

通过查看:每秒上下文切换次数 四万多

2.查看项目线程状态

让测试重新开始压测,通过arthas命令查看当前项目占用线程状态(thread)

可以看到大部分进程进入BLOCKED状态,进入tomcat线程查看堆栈信息。

可以看出具体阻塞的原因是tomcatEmbeddedClassLoader

3.查看出现锁的具体源码

投机取巧,先对loadClass进行watch操作,查看详细的出入参数

[arthas@31524]$ watch org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader loadClass '{params,returnObj,throwExp}' -n 5 -x 3 ts=2022-09-13 15:47:38; [cost=2.3656858288008095E10ms] result=@ArrayList[ts=2022-09-13 15:47:38; [cost=2.3656858286638813E10ms] result=@ArrayList[ts=2022-09-13 15:47:38; [cost=2.3656858287444527E10ms] result=@ArrayList[ts=2022-09-13 15:47:38; [cost=2.3656858286489414E10ms] result=@ArrayList[ @Object[][ @String[org.springframework.cloud.context.environment.EnvironmentChangeEvent], @Boolean[false], ], null, java.lang.ClassNotFoundException: org.springframework.cloud.context.environment.EnvironmentChangeEvent at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader.loadClass(TomcatEmbeddedWebappClassLoader.java:68) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.springframework.util.ClassUtils.forName(ClassUtils.java:280) @Object[][ at com.ulisesbocchio.jasyptspringboot.caching.RefreshScopeRefreshedEventListener.isAssignable(RefreshScopeRefreshedEventListener.java:45) @String[org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent], at com.ulisesbocchio.jasyptspringboot.caching.RefreshScopeRefreshedEventListener.onApplicationEvent(RefreshScopeRefreshedEventListener.java:31) at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) @Boolean[false], ], null,at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) java.lang.ClassNotFoundException: org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEventat org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader.loadClass(TomcatEmbeddedWebappClassLoader.java:68) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1188) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.springframework.util.ClassUtils.forName(ClassUtils.java:280) ts=2022-09-13 15:47:38; [cost=2.3656858287126102E10ms] result=@ArrayList[at com.ulisesbocchio.jasyptspringboot.caching.RefreshScopeRefreshedEventListener.isAssignable(RefreshScopeRefreshedEventListener.java:45)

可以看出参数为org.springframework.cloud.context.environment.EnvironmentChangeEvent。

并且抛出的异常为找不到org.springframework.cloud.context.environment.EnvironmentChangeEvent此类。

回归死锁堆栈信息

回顾tomcat实现的原理

tomcat对请求到的请求会进行封装

doPost->封装成event->由指定event监听进行处理此请求。

在详细的信息中可以看到ApplicationListener由RefreshScopeRefreshedEventListener实现,并且其中isAssignable出现了死锁。

其中的className为org.springframework.cloud.context.environment.EnvironmentChangeEvent。

也就是watch报错的参数。

并且可以看到这个包并非tomcat自己实现的包,而是第三方包com.ulisesbocchio.jasyptspringboot.caching

4.排查出错的包

查看包的详细

通过pom寻找,查到我们导入了他的依赖

并且进行了stater注入

解决

问题一:org.springframework.cloud.context.environment.EnvironmentChangeEvent 类

BAS平台项目不是分布式服务,没有此类,所以这就是导致死锁报错的原因。

是否需要引入cloud组件来解决此问题

问题二:是否可以修改此依赖来解决

当前版本为3.0.3

com.github.ulisesbocchio

jasypt-spring-boot

${jasypt.version}

目前去除了stater版本,改为此依赖。

打包部署后,测试重新压测。TPS达到了8K多。

但是修改此依赖导致其他配置要修改(如密码明文配置等)还需要重新适配

问题三:是否已经出现版本适配此bug

通过查询

官方已经发现此问题,升级到3.0.4即可