我一直在寻找导致Tomcat服务器间歇性减速的原因。我们每周有几次慢下来,Tomcat将停止响应或花费几分钟来处理请求,并且(Linux)机器上的cpu负载(如正常运行时间所示)通常从1到2上升到超过30。然后,事情逐渐解决了自己和一切恢复正常后,可能10分钟左右。
我们使用Apache作为前端,将Postgres用作数据库。我一直在挖掘日志,试图找出导致问题的原因。在经济放缓时期,我没有注意到需求有明显的增长。
我所发现的是,在经济放缓之前,Tomcat在多个场合下似乎只是睡了大约3.5分钟。在这段时间里,它的日志中没有条目,也没有从Tomcat到数据库的查询。在小小的午睡之后,Tomcat会醒过来,开始疯狂地尝试处理所有备份的内容,这会导致大量的数据库和cpu加载,以及缓慢的响应时间。
为了弄清楚Tomcat在午睡期间在做什么,我设置了一个脚本来监视它的日志,并发送一个杀害-3信号,如果日志中有三分钟没有活动,就发送一个线程转储。不幸的是,信号不会唤醒Tomcat,所以线程转储直到它自己唤醒并恢复处理之后才会发生。
Apache和Postgres显然还在三分钟半的间隙中保持清醒和活跃--他们的日志显示,与Tomcat无关的活动在这段时间内仍在继续。
我们的Tomcat版本是5.0.28。
想法,建议?我刚开始和Tomcat一起工作,所以请不要以为我有太多的知识。
根据Alex的建议激活详细的垃圾收集之后,我捕捉到了一些问题的发生,发现一个完整的GC负责,在这两种情况下花费了超过200秒,例如:
04:21:55.648491500 [GC 1035796K->933637K(1041984K), 0.3407580 secs]
04:21:56.012832500 [Full GC[Unloading class sun.reflect.GeneratedMethodAccessor633]
04:22:38.003920500 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor39]
04:22:38.004051500 [Unloading class sun.reflect.GeneratedConstructorAccessor102]
04:22:38.004392500 [Unloading class sun.reflect.GeneratedConstructorAccessor98]
04:22:38.004533500 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor40]
04:22:38.004716500 [Unloading class sun.reflect.GeneratedMethodAccessor634]
04:22:38.004808500 [Unloading class sun.reflect.GeneratedConstructorAccessor90]
04:22:38.004889500 [Unloading class sun.reflect.GeneratedConstructorAccessor95]
04:22:38.005044500 [Unloading class sun.reflect.GeneratedMethodAccessor632]
04:25:18.688916500 933637K->154281K(1041984K), 202.6760940 secs]现在我只需要弄清楚如何调整事情来防止这种情况发生。(欢迎提出建议。)
谢谢你的帮助亚历克斯和梅盖伊。
发布于 2010-08-28 12:10:25
如前所述,第一步是更改tomcat启动脚本以添加
-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails 当你有你的减速,寻找在catalina.out的东西,如"FullGC“或许多GCs.
我会注意到,如果您还没有这样做,请将tomcat堆的大小提高到大约1/2到3/4的可用内存,假设这个框刚刚运行tomcat。例如,要将最大堆设置为768兆字节,可以添加:
-Xmx768M转到JAVA_OPTS
如果使用ubuntu10.04,这些设置通常位于/etc/default/tomcat6 6中。
发布于 2010-08-30 20:57:15
当Java堆的“永久”生成中的一大块内存被交换到磁盘上时,就发生了这种情况,因为它是垃圾,已经有一段时间没有使用了。当需要完整的集合时,必须将该内存交换回。
在这种情况下,您的回答有点违背直觉:缩小Java堆的大小,或者找出其他什么东西正在使用导致交换的RAM。在我们的例子中,一些夜间批处理作业使用了一堆RAM,导致老一代被交换到磁盘上。因此,第二天早上需要的第一个完整的GC需要花费很长时间(180+秒,正如您所看到的)。
您还可以尝试并发标记扫描收集器,它通过并行执行大量工作来减少GC的全部时间。这是我见过的最好的文档;还有一些关于这个主题的优秀Sun博客:http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
发布于 2010-08-27 17:33:52
尝试激活详细的垃圾收集,看看是否是垃圾收集暂停。我想巨大的堆、大量的对象分配和交换可能会导致很长时间的停顿,但这段时间听起来很不寻常。
https://serverfault.com/questions/175372
复制相似问题