这是Tomcat 6.0.18,Java 1.7.0_03(32位)和SLES11 SP2(64位)。 至于内核信息:
$ uname -a Linux server-1 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux
我们正在三台服务器上进行负载和长寿testing。 在所有三台独立的机器上,当每个Tomcat启动时,Tomcat在2 ^ 32毫秒(49天以上)的一秒内退出。 在每台机器上,两个线程在JVM退出之前产生堆栈跟踪(Tomcat本身在得到SocketTimeoutException这是JVM退出的原因System.exit(1)时调用System.exit(1) )。
一个线程是(默认情况下)在端口8005上侦听closures命令(通过查看Tomcat源validation):
Jun 22, 2012 9:10:15 AM org.apache.catalina.core.StandardServer await SEVERE: StandardServer.await: accept: java.net.SocketTimeoutException: Accept timed out at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.AbstractPlainSocketImpl.accept(Unknown Source) at java.net.ServerSocket.implAccept(Unknown Source) at java.net.ServerSocket.accept(Unknown Source) at org.apache.catalina.core.StandardServer.await(StandardServer.java:389) at org.apache.catalina.startup.Catalina.await(Catalina.java:642) at org.apache.catalina.startup.Catalina.start(Catalina.java:602) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
另一个线程是(我们相信,虽然我们没有检查Tomcat源来validation)处理传入端口8080连接的线程:
Jun 22, 2012 9:10:15 AM org.apache.jk.common.ChannelSocket acceptConnections WARNING: Exception executing accept java.net.SocketTimeoutException: Accept timed out at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.AbstractPlainSocketImpl.accept(Unknown Source) at java.net.ServerSocket.implAccept(Unknown Source) at java.net.ServerSocket.accept(Unknown Source) at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:307) at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:661) at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:872) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690) at java.lang.Thread.run(Unknown Source)
Tomcat没有做任何事情。 在第一种情况下,它只是一个通过调用ServerSocket.accept()和accept()调用炸弹来获取Socket的while (true)循环。
任何想法,为什么发生这种情况,我可以尝试看看/为了弄清楚如何防止它在未来?
请注意,当Tomcat运行2 ^ 32毫秒时,当Tomcat启动时,系统已经启动。 当然,这并不排除Tomcat开始涉及时创build的一些过程variables。
我最近也看到了这个问题,它似乎与Java 6和7之间的32位Oracle JVM所做的更改相隔离。在Linux上,使用strace运行32位Java 7 VM显示以下系统调用当调用ServerSocket.accept()而没有设置SO_TIMEOUT时:
32369 poll([{fd=5, events=POLLIN|POLLERR}], 1, 4294967295 <unfinished ...>
对poll()的调用传递2 ^ 32毫秒(4294967295)的超时值,而不是预期的负值,这将表示无限超时。 这最终导致ServerSocket.accept()抛出一个SocketTimeoutException,这导致Tomcat的引导代码执行closures服务器。 那个特定的Tomcat永远不会期望ServerSocket.accept抛出SocketTimeoutException。
如果可以操作poll()的调用,以便不必等待2 ^ 32毫秒,则更容易重现此问题。 这可以通过重写轮询系统调用在Linux中完成。 执行此操作的一种方法是使用LD_PRELOAD指令加载轮询的重写版本。 显示这个想法的一些示例代码可以在https://github.com/vi/timeskewfind。 不幸的是,它不会覆盖民意调查,但可以很容易地扩展到这样做。
我在使用64位Debian Linux上的Tomcat 7.0.35和Java 1.7.0_10(32位)时遇到了同样的问题。
在我的情况下,更新和使用64位JDK解决了这个问题