JVM在RHEL 5.2上承受压力时崩溃

10

我正在运行一个Web应用程序,使用目前最新版本的JDK 1.6.0.18和Tomcat 6.0.24,在RHEL 5.2(Tikanga)上进行压力测试(30个线程每天访问600万次页面),但在4小时到8天后意外崩溃。崩溃报告在http://pastebin.com/f639a6cf1,其中一致的部分是:

  • 抛出了SIGSEGV异常
  • 发生在libjvm.so上
  • eden空间总是满的(100%)

JVM使用以下选项运行:

CATALINA_OPTS="-server -Xms512m -Xmx1024m -Djava.awt.headless=true"

我还使用了http://memtest.org/测试硬件内存是否存在问题,连续运行了48小时(整个内存的14次通过),没有发现任何错误。

我启用了-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps以检查是否存在GC趋势或空间不足,但没有发现任何可疑的情况。GC和full GC会在可预测的间隔时间内发生,几乎总是释放相同数量的内存容量。

我的应用程序没有直接使用任何本地代码。

您有任何想要建议我接下来该去哪里寻找问题的想法吗?

编辑-更多信息:

1)这个JDK中没有客户端vm:

[foo@localhost ~]$ java -version -server
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

[foo@localhost ~]$ java -version -client
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

2) 更改操作系统不可行。

3) 我不想更改JMeter压力测试变量,因为这可能会隐藏问题。由于我有一个使用案例(当前的压力测试场景)会导致JVM崩溃,所以我想修复崩溃而不是更改测试。

4) 我已经对我的应用程序进行了静态分析,但没有发现任何严重问题。

5) 内存不会随时间增长。内存使用在启动后非常快速地平衡,并且保持着稳定的趋势,看起来并不可疑。

6) /var/log/messages 在崩溃之前或期间没有包含任何有用的信息。

更多信息:我忘记提到,有一个Apache(2.2.14)前置Tomcat,使用 mod_jk 1.2.28。现在我正在不使用Apache的情况下运行测试,以防JVM崩溃与连接到JVM(Tomcat连接器)的mod_jk本机代码有关。

之后(如果JVM再次崩溃),我将尝试从我的应用程序中删除一些组件(缓存、lucene、quartz),然后尝试使用Jetty。由于崩溃当前发生的时间在4小时到8天之间,可能需要很长时间才能找出问题所在。


1
这需要发送给<del>Sun</del> Oracle。 - bmargulies
@bmargulies: 这是我最初想到的,但后来我阅读了https://dev59.com/lUnSa4cB1Zd3GeqPLCDq - cherouvim
1
假设您使用最新的JDK,您是否尝试使用VisualVM实时研究其行为?我们发现它比第三方分析工具更有效地调查泄漏问题。 - Uri
@Uri:感谢提到 VisualVM。看起来很有意思。 - cherouvim
没问题。我们一直非常满意它,特别是与我们以前使用过的工具相比。唯一需要花费很长时间的事情是加载堆转储。但是您可以让分析器对内存进行分析而不是性能,并且它实际上会跟踪创建哪些对象 - 对于跟踪内存泄漏非常有用。如果您能负担得起,请确保增加VisualVM的可用堆大小。 - Uri
7个回答

4
您有编译器输出吗?例如PrintCompilation(如果您感到特别勇敢,还可以使用LogCompilation)。
我曾经通过观察编译器的操作来调试过类似这样的情况,并最终(这花了很长时间直到恍然大悟的时刻)意识到我的崩溃是由于编译Oracle JDBC驱动程序中的某个方法引起的。
基本上,我会这样做:
  • 打开PrintCompilation
  • 因为它不提供时间戳,所以编写一个脚本来监视该日志文件(如每秒钟睡眠并打印新行),并在编译方法时报告方法是否已编译(或未编译)
  • 重复测试
  • 检查编译器输出,看看崩溃是否与某些方法的编译相对应
  • 再次重复几次,看是否存在模式
如果存在可辨别的模式,则使用.hotspot_compiler(或.hotspotrc)使其停止编译有问题的方法,然后重复测试并查看是否会出现问题。显然,在您的情况下,这个过程理论上可能需要数月的时间。
一些参考资料: 另一件事是系统地更改您正在使用的GC算法,并检查崩溃时间与GC活动(例如,是否与young或old GC相关,TLABs如何?)相关。您的转储表明您正在使用并行清除收集器,因此请尝试:
  • 串行(年轻)收集器(如果我没记错,它可以与并行旧收集器结合使用)
  • ParNew + CMS
  • G1

如果使用不同的GC算法后问题没有再次出现,那么你就知道问题出在这个算法上(你只能改变GC算法或者回退到旧版本的JVM,直到找到一个不会出问题的算法版本)。


感谢您让我注意到PrintCompilation。我一定会尝试一下。 - cherouvim

3

几个想法:

  • 使用不同的JDK、Tomcat和/或操作系统版本
  • 稍微修改测试参数,例如每天7.2M页面浏览量下的25个线程
  • 监控或分析内存使用情况
  • 调试或优化垃圾回收器
  • 运行静态和动态分析

2

您尝试过不同的硬件吗?看起来您正在使用64位架构。根据我的经验,32位系统更快、更稳定。也许某些硬件出了问题。在“4-24小时之间”的时间范围内,单纯的软件问题并不会如此广泛。虽然您说系统日志中没有错误,但我认为还是值得尝试。


尝试不同的硬件并不是一个选择,但我会尝试32位的JVM。谢谢。 - cherouvim

1

你的内存会随着时间增长吗?如果是这样,我建议将内存限制降低,看看系统在内存耗尽时是否更频繁地出现故障。

如果你:

  • 减少JVM可用内存?
  • 减少可用系统资源(即耗尽系统内存,使JVM不足)?
  • 将你的用例更改为更简单的模型?

能更快地复现问题吗?

我使用的主要策略之一是确定哪个用例导致了问题。它可能是一个通用问题,也可能是用例特定的问题。尝试记录用例的启动和停止,看看你是否可以确定哪些用例更有可能导致问题。如果你将你的用例分成两半,看看哪一半失败得最快。那很可能是故障的更频繁原因。当然,运行每个配置的几次试验将提高你的测量精度。

我还会改变服务器的工作方式,让其做更少的工作或者循环执行服务器正在执行的工作。一个让你的应用程序代码更加努力工作,另一个则让Web服务器和应用服务器更加努力工作。

祝你好运, Jacob


根据您的跟踪,系统内存在这种情况下不应该是问题。系统日志中是否有任何消息?此外,如果我读得正确,似乎您可能有相当多的线程正在运行。在任何给定时间,有大量线程在等待可用的CPU。我希望使用较少的线程可以获得更快的平均响应时间。 - TheJacobTaylor

1

要查看JVM是否仍会崩溃?还是完全迁移到Jetty? - cherouvim
我会选择完全迁移到Jetty,因为我喜欢过去所看到的Jetty。 然而,我刚刚谷歌搜索的最新比较显示性能方面Jetty-6与Tomcat-6相当,尽管Jetty似乎具有更轻的内存占用。 从更系统化的方法来看,只要您的应用程序符合标准,迁移就不应该太困难,然后您可以消除容器作为根本原因或验证应用程序作为根本原因。祝你好运。 - crowne
1
感谢您的评论。我的应用程序与所有主要的服务器(包括tomcat、jboss、resin、jetty和glashfish)兼容,因此迁移不是问题。我一定会在Jetty上尝试压力测试。 - cherouvim

1

如果我是你,我会做以下几点:

  • 尝试使用稍旧的Tomcat/JVM版本。你似乎正在运行最新和最好的版本。我会降低两个版本或者尝试JRockit JVM。
  • 在应用程序运行时执行线程转储(kill -3 java_pid)以查看完整的堆栈。您当前的转储显示有很多线程被阻塞,但不清楚它们在哪里被阻塞(I/O?一些内部锁饥饿?还是其他什么原因?)。我甚至可能会安排每分钟运行一次“kill -3”,以将任意随机线程转储与崩溃前的线程转储进行比较。
  • 我曾经见过Linux JDK死亡的情况,而Windows JDK能够优雅地捕获异常(当时是StackOverflowException),因此如果您可以修改代码,请在顶级类中添加“catch Throwable”。以防万一。
  • 尝试GC调优选项。打开/关闭并发GC,调整NewSize/MaxNewSize。是的,这不是科学的,而是迫切需要工作解决方案。更多详细信息请参见:http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

请告诉我们这个问题是如何解决的!


1

是否考虑使用32位JVM呢?我认为这是Sun公司最成熟的产品。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接