在Tomcat上以WAR部署的Spring Boot应用程序中增加的类加载计数

时间:2019-09-23 05:13:15

标签: java performance spring-boot tomcat

我们有一个运行在Tomcat上的Spring Boot应用程序,它是一个RESTful Web服务。在我们的测试环境和生产环境中,相同的WAR文件部署在3个Tomcat实例上。在运行性能测试时,我们注意到某些服务器存在一个特殊问题。一些服务器在处理大约2500个请求后停止响应。此问题在3个生产服务器中的2个发生,在3个测试服务器中的1个中发生。

在有问题的服务器上,我们在JVM监视中注意到,每当我们运行性能测试时,已装入的类数就不断增加。上课人数从2万增加到200万左右。当类计数接近200万时,JVM监视也显示GC花费的时间太长,超过40秒。一旦达到该点,应用程序将停止响应。应用程序抛出OutOfMemoryException“压缩类空间”。如果我们继续发送更多请求,则从应用程序日志中可以看到该服务仍在接收请求,但中途停止处理。

在没有问题的其他服务器上,类加载计数保持恒定20k。 GC也很正常,花费不到1秒。

我们注意到的其他测试和行为-

  1. 此问题发生在Windows PC上安装的本地Tomcat实例上。服务器在Linux上。此问题在OpenJDK和Oracle JDK 1.8上均会发生。
  2. 我们验证了Tomcat实例是否彼此相同-甚至从工作服务器中克隆了它们,并将它们放在故障服务器上。
  3. 使用不同的GC策略进行了测试-PS,CMS和G1,并且所有这三个问题均发生。
  4. 通过将应用程序作为独立的Spring Boot JAR运行来进行测试,问题消失了。类计数保持不变,GC正常运行。
  5. 该应用程序当前正在使用JAXB库执行XML编组/解组,我们在代码中找到了可以优化代码的地方。重构代码并移至Jackson库是另一种选择。

我的问题是-

  • 当我们部署相同的WAR文件时,会导致多台服务器之间出现差异的原因是什么。
  • 在Tomcat上以WAR形式运行的应用程序与以独立的Spring Boot应用程序形式运行的应用程序之间的区别将是什么?
  • 如果我们对JVM进行堆转储或进行概要分析,那么要注意什么?

1 个答案:

答案 0 :(得分:0)

因此,事实证明这是由于我们的类路径中的jaxb 2.1 jar引起的。感谢Mark指出了jaxb的已知错误。

我们的应用程序没有明确将jaxb-impl作为依赖项,因此一开始很难看到。查看Maven依赖树后,我们发现正在从其他项目和库中加载两个不同的版本。我们的应用程序在类路径中具有jaxb-impl版本2.1和2.2.6。我们将2.1版本排除在应用程序的pom.xml中,从而解决了该问题。

我的猜测是,在应用程序启动时,不同的服务器正在加载不同的版本。这可能就是为什么某些服务器运行正常,而其他加载2.1版本的服务器出现问题的原因。与作为独立的Spring Boot应用程序运行类似,它可能已经加载了2.1版本。