Tomcat启动失败,原因是';java.net.SocketException无效参数';在MacOSX上

Tomcat启动失败,原因是';java.net.SocketException无效参数';在MacOSX上,tomcat,java-native-interface,java,Tomcat,Java Native Interface,Java,我们有一个在Tomcat 6上运行的应用程序(准确地说是6.0.35.0),我们在Mac OS上的大多数工程师在启动Tomcat时都遇到问题,因为Catalina.await方法中的socketAccept调用抛出了SocketException: SEVERE: StandardServer.await: accept: java.net.SocketException: Invalid argument at java.net.PlainSocketImpl.socketAcce

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

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在启动后立即关闭(并且非常愤怒)。 我们认为这在MacOSW/Java1.7上已经持续了一段时间,在过去的几个月里,我们中的很多人都转向MacBookPros。到目前为止,唯一的症状是来自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  
这个问题对时间很敏感。由于应用程序更改而增加的启动时间(更多的Spring内省/单例开销)似乎是影响Tomcat启动的因素;引爆点约为160秒。我们可以通过禁用一些在开发过程中不需要的非强制性上下文来减少启动时间,从而缓解问题,但我更愿意找到根本原因

应用程序配置 应用程序的细节太复杂了,不可能太详细,但我有一种预感,这可能与早期绑定有关,因此我至少会列出我机器上的侦听端口:

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回归。我已经测试了JDK1.7.0_09、11、15、17和21(在此期间我在机器上安装的JDK)
  • Mac操作系统更新。Mac OS 10.7.x和10.8.0至1.8.3受到影响
  • 文件描述符限制-从
    5000
    增加到
    10000
  • 在主以太网接口上完全禁用IPv6
  • 设置断点,并删除第一个受SocketException影响的上下文(它们是对web服务的传出HTTP调用)。不变
  • 配置
    /etc/hosts
    使机器主机名解析为localhost,并配置JVM选项以首选IPv4而不首选IPv6地址(此答案:)
对于那些对主机配置感兴趣的人来说,这与默认设置相同。我可以在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代码调查 由于问题具有明显的时间敏感性,设置断点对问题进行故障排除会导致问题不会发生。根据评论中的要求,我还为
socksocketimpl(PlainSocketImpl).socketAccept(SocketImpl)
捕获了
arg0
,似乎没有什么异常

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让我确信触发器可能是执行基于套接字的操作的某个预定任务,这会影响其他套接字操作

这并不能解释这会如何以及为什么会影响多个线程,无论我们如何导致这种情况,神秘的SocketException不应该从本机代码中冒出来,并在多个线程上同时导致这些异常-也就是说,两个线程发出web服务调用,Tomcat等待调用,和多个TP处理器线程重复

JNI代码调查 给定一般消息,我假设socketAccept JNI代码中的一个系统调用必须返回
EINVAL
错误,因此我跟踪了导致异常的系统调用;任何系统调用都不会返回
EINVAL
。因此,我去OpenJDK源代码中查找socketAccept代码中的条件,该代码将设置并抛出一个
EINVAL
,但我也找不到任何将
errno
设置为
EINVAL
,或调用
NET\u ThrowByNameWithLastError
的代码,
NET\u ThrowCurrent
NET\u ThrowNew
的方式会引发带有此默认错误消息的SocketException

就系统调用而言,我们似乎没有达到接受系统调用的程度:

 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
因此,我认为问题发生在
socketAccept
中accept循环顶部的超时处理代码中,但我找不到
NET\u timeout
errno
设置为
EINVAL
并导致抛出此SocketException的任何情况。我指的是这个代码;我假设jdk7u分支在很大程度上是Oracle JDK中提供的:

救命啊! 我在外界找不到任何人受到Mac OS上这个特殊问题的影响,但这里几乎每个人都受到影响。一定有一些应用程序配置是有帮助的,但我已经用尽了我能想到的所有方法来找到根本原因


如果能提供故障排除方面的提示或对可能原因的洞察,我将不胜感激。

我也遇到了同样的问题(使用Tomcat7),而且似乎对我有效的方法是在Eclipse中运行tomcat时勾选“发布模块上下文以分离XML文件”选项。你已经试过了吗?

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

  • 使用下一个覆盖更新/etc/hosts:
    • ::1 EWD-MacBook-Pro.local
    • 127.0.0.1 EWD-MacBook-Pro.local本地主机
(EWD-MacBook-Pro.local是我的机器名)

  • 设置系统属性:
    • java.net.prefe
       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
      
      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();
        }
      }