由于Mac OS X上的“java.net.SocketException Invalid argument”,Tomcat启动失败

时间:2013-04-24 11:48:59

标签: tomcat java-native-interface java

我们有一个在Tomcat 6上运行的应用程序(确切地说是6.0.35.0),由于Catalina.await方法中的socketAccept调用抛出SocketException,我们在Mac OS上的大多数工程师都遇到启动Tomcat的问题: / p>

SEVERE: StandardServer.await: accept:
java.net.SocketException: Invalid argument
      at java.net.PlainSocketImpl.socketAccept(Native Method)
      at java.net.PlainSocketImpl.socketAccept(PlainSocketImpl.java)
      at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
      at java.net.ServerSocket.implAccept(ServerSocket.java:522)
      at java.net.ServerSocket.accept(ServerSocket.java:490)
      at org.apache.catalina.core.StandardServer.await(StandardServer.java:431)
      at org.apache.catalina.startup.Catalina.await(Catalina.java:676)
      at org.apache.catalina.startup.Catalina.start(Catalina.java:628)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:601)
      at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
      at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
      at mycompany.tomcat.startup.ThreadDumpWrapper.main(ThreadDumpWrapper.java:260)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:601)
      at org.tanukisoftware.wrapper.WrapperStartStopApp.run(WrapperStartStopApp.java:238)
      at java.lang.Thread.run(Thread.java:722)

这会导致Tomcat在启动后立即关闭(并且没有少量的愤怒)。 我们认为这在Mac OS w / Java 1.7上一直存在,在过去的几个月里,我们很多人已经转向Macbook Pros。到目前为止,唯一的症状是来自Tomcat的偶然零字节响应,因为这个异常也被抛出在socketRead上。错误没有击中日志,我们单独将其作为一个孤立的问题耸了耸肩,并且只在启动问题开始时找到了原因并设置了SocketException断点:

Daemon Thread [http-8080-1] (Suspended (breakpoint at line 47 in SocketException))  
  SocketException.<init>(String) line: 47 
  SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available [native method] 
  SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available  
  SocketInputStream.read(byte[], int, int, int) line: 150 
  SocketInputStream.read(byte[], int, int) line: 121  
  InternalInputBuffer.fill() line: 735  
  InternalInputBuffer.parseRequestLine() line: 366  
  Http11Processor.process(Socket) line: 814 
  Http11Protocol$Http11ConnectionHandler.process(Socket) line: 602  
  JIoEndpoint$Worker.run() line: 489  
  Thread.run() line: 722  

对于论点:

arg0  FileDescriptor  (id=499)  
  fd  1097  
  useCount  AtomicInteger  (id=503) 
    value 2 
arg1  (id=502)
arg2  0 
arg3  8192  
arg4  20000 

问题是时间敏感的。由于应用程序的更改而增加启动时间(更多的Spring内省/单例开销)似乎是导致这会影响Tomcat启动的因素;临界点约为160秒。我们可以通过禁用开发过程中不需要的一些非强制性上下文来减少启动时间来缓解问题,但我更愿意找到根本原因。

应用程序配置

应用程序的细节太复杂而无法详细说明,但我有一种预感,这可能与早期的绑定有关,所以我至少列出了我机器上的监听端口: / p>

localhost:32000 - Java service wrapper port
*:10001         - RMI registry
*:2322          - Java debug
*:56566         - RMI
*:8180          - Tomcat HTTP connector
*:8543          - Tomcat HTTPS connector
*:2223          - Tomcat Internal HTTP connector (used for cross-server requests)
*:14131         - 'Locking' port to determine if an internal service is running
*:56571         - EhCache RMI
*:56573         - RMI
*:62616         - ActiveMQ broker
*:5001          - SOAPMonitorService
*:8109          - Tomcat shutdown port

排除的项目

  • 最明显的解决方案:-Djava.net.preferIPv4Stack=true。我一直都配置了该选项
  • 我们的基本应用程序配置,库,JVM选项的任何最新配置更改(没有任何内容)
  • JDK回归。我已经测试过JDK 1.7.0_09,11,15,17和21(我已经在我的机器上安装了JDK)
  • Mac OS更新。 Mac OS 10.7.x和10.8.0到1.8.3受到影响
  • 文件描述符限制 - 从5000增加到10000
  • 在主以太网接口上完全禁用IPv6
  • 设置断点,并删除受SocketException影响的第一个上下文(它们是对Web服务的传出HTTP调用)。没有变化
  • 配置/etc/hosts以使计算机主机名解析为localhost,并将JVM选项配置为首选IPv4而更喜欢IPv6地址(此答案:https://stackoverflow.com/a/16318860/364206

对于那些对主机配置感兴趣的人,它与默认配置相同。我可以在Fusion VM上重现这一点,干净安装10.8:

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0 localhost

Java代码调查

由于问题的明显时间敏感性,设置断点以解决问题导致它不会发生。根据评论中的要求,我还为arg0捕获了SocksSocketImpl(PlainSocketImpl).socketAccept(SocketImpl),似乎没有什么不寻常的。

arg0  SocksSocketImpl  (id=460) 
  address InetAddress  (id=465) 
    canonicalHostName null  
    holder  InetAddress$InetAddressHolder  (id=475) 
      address 0 
      family  0 
      hostName  null  
  applicationSetProxy false 
  closePending  false 
  cmdIn null  
  cmdOut  null  
  cmdsock null  
  CONNECTION_NOT_RESET  0 
  CONNECTION_RESET  2 
  CONNECTION_RESET_PENDING  1 
  external_address  null  
  fd  FileDescriptor  (id=713)  
    fd  -1  
    useCount  AtomicInteger  (id=771) 
      value 0 
  fdLock  Object  (id=714)  
  fdUseCount  0 
  localport 0 
  port  0 
  resetLock Object  (id=716)  
  resetState  0 
  server  null  
  serverPort  1080  
  serverSocket  null  
  shut_rd false 
  shut_wr false 
  socket  Socket  (id=718)  
    bound false 
    closed  false 
    closeLock Object  (id=848)  
    connected false 
    created false 
    impl  null  
    oldImpl false 
    shutIn  false 
    shutOut false 
  socketInputStream null  
  stream  false 
  timeout 0 
  trafficClass  0 
  useV4 false 

我认为抛出异常的所有线程都是早期调用的受害者,这个调用没有导致SocketException,因此我无法捕获它。能够通过减少启动时间来启动Tomcat使我相信触发器可能是一些执行基于套接字的操作的计划任务,然后影响其他套接字操作。

这并没有解释这可能会影响多个线程的方式和原因,无论我们采取什么措施来引起这种情况,神秘的SocketExceptions都不应该从本机代码中冒出来并同时导致这些异常在多个线程上 - 即两个线程进行传出Web服务调用,Tomcat等待调用,以及多个TP处理器线程重复。

JNI代码调查

鉴于通用消息,我假设必须从socketAccept JNI代码中的一个系统调用返回EINVAL错误,因此我跟踪导致异常的系统调用;任何系统调用都没有返回EINVAL。所以,我去OpenJDK源寻找socketAccept代码中的条件,该代码将设置然后抛出EINVAL,但我也找不到任何将errno设置为{{1}的代码或者以一种使用此默认错误消息抛出SocketException的方式调用EINVALNET_ThrowByNameWithLastErrorNET_ThrowCurrent

就系统调用而言,我们似乎无法接受接受系统调用:

NET_ThrowNew

所以,我认为问题发生在 PID/THRD RELATIVE ELAPSD CPU SYSCALL(args) = return 6606/0x2c750d: 221538243 5 0 sigprocmask(0x1, 0x0, 0x14D8BE100) = 0x0 0 6606/0x2c750d: 221538244 3 0 sigaltstack(0x0, 0x14D8BE0F0, 0x0) = 0 0 6606/0x2c750d: 221538836 14 10 socket(0x2, 0x1, 0x0) = 1170 0 6606/0x2c750d: 221538837 3 0 fcntl(0x492, 0x3, 0x4) = 2 0 6606/0x2c750d: 221538839 3 1 fcntl(0x492, 0x4, 0x6) = 0 0 6606/0x2c750d: 221538842 5 2 setsockopt(0x492, 0xFFFF, 0x4) = 0 0 6606/0x2c750d: 221538852 7 4 bind(0x492, 0x14D8BE5D8, 0x10) = 0 0 6606/0x2c750d: 221538857 5 2 listen(0x492, 0x1, 0x4) = 0 0 6606/0x2c750d: 221539625 6 2 psynch_cvsignal(0x7FEFBFE00868, 0x10000000200, 0x100) = 257 0 6606/0x2c750d: 221539633 4 1 write(0x2, "Apr 18, 2013 11:05:35 AM org.apache.catalina.core.StandardServer await\nSEVERE: StandardServer.await: accept: \njava.net.SocketException: Invalid argument\n\tat java.net.PlainSocketImpl.socketAccept(Native Method)\n\tat java.net.PlainSocketImpl.socketAcce", 0x644) = 1604 0 中接受循环顶部的超时处理代码中,但我找不到{{1}的任何情况将socketAccept设置为NET_Timeout,并导致抛出此SocketException。我指的是这段代码;我假设jdk7u分支大部分是Oracle JDK中的内容:

帮助!

我无法在Mac OS上找到受此特定问题影响的外界人士,但此处几乎每个人都受到影响。必须有一些应用程序配置有所贡献,但我已经用尽了我能想到的每个途径来找到根本原因。

非常感谢有关故障排除或对可能原因的见解的指示。

4 个答案:

答案 0 :(得分:21)

您是否使用-Xcheck:jni尝试了turning on JNI debugging?有趣的是,Oracle documentation使用PlainSocketImpl.socketAccept错误作为何时使用此错误的示例。

另请注意,Bug 7131399的含义是,由于Mac上的poll()存在问题,JNI在大多数平台上使用select()但在Mac OS上使用poll()。所以也许select()也被打破了。进一步挖掘,如果&#34; ndfs大于FD_SETSIZE并且未定义_DARWIN_UNLIMITED_SELECT,则select()将返回EINVAL。&#34; FD_SETSIZE是1024,听起来你有大量的应用程序加载,所以也许所有过滤器一直等待更多的1024个FD。

要获得额外赠送金额,请查看您的计算机上是否已修复the related (supposedly fixed) Java bug。错误报告指向测试用例。


感谢Old Pro的回答,我确认select() FD_SETSIZE限制是原因。我找到了这个限制的现有错误:

https://bugs.openjdk.java.net/browse/JDK-8021820

可以使用以下代码重现该问题:

import java.io.*;
import java.net.*;

public class SelectTest {
  public static void main(String[] args) throws Exception {
    // Use 1024 file descriptors. There'll already be some in use, obviously, but this guarantees the problem will occur
    for(int i = 0; i < 1024; i++) {
      new FileInputStream("/dev/null");
    }
    ServerSocket socket = new ServerSocket(8080);
    socket.accept();
  }
}

差不多一年后,Java 7u60解决了这个问题:

http://www.oracle.com/technetwork/java/javase/2col/7u60-bugfixes-2202029.html

我还发现Tomcat的WebappClassLoader在90秒后关闭了文件句柄,这解释了为什么设置断点可以防止问题发生。

答案 1 :(得分:1)

我有完全相同的问题(使用Tomcat7),对我来说似乎是在我在Eclipse中运行tomcat时勾选“发布模块上下文以分离XML文件”选项。你已经试过了吗?

答案 2 :(得分:1)

答案 3 :(得分:0)

我在另一个环境中一直在与这个问题作斗争。来自不同来源的解决方案如下所示:

  • 使用下一个覆盖更新/ etc / hosts:
    • :: 1 EWD-MacBook-Pro.local
    • 127.0.0.1 EWD-MacBook-Pro.local localhost

(EWD-MacBook-Pro.local是我的机器名称)

  • 设置系统属性:
    • java.net.preferIPv4Stack =&gt;真
    • java.net.preferIPv6Addresses =&gt;假
祝你好运!