首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >由于Mac上的“java.net.SocketException无效参数”,Tomcat启动失败

由于Mac上的“java.net.SocketException无效参数”,Tomcat启动失败
EN

Stack Overflow用户
提问于 2013-04-24 11:48:58
回答 4查看 15.2K关注 0票数 29

我们有一个运行在Tomcat 6上的应用程序(确切地说,是6.0.35.0),而且我们在Mac上的大多数工程师在启动Tomcat时遇到了问题,原因是Catalina.await方法中的Catalina.await调用引发了SocketException:

代码语言:javascript
复制
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在启动后立即关闭(而不是少量的愤怒)。我们认为,在Macbook /Java1.7上,这种情况一直存在,在过去几个月中,我们中的许多人已经转向Macbook Pros。到目前为止,唯一的症状是来自Tomcat的偶尔的零字节响应,因为这个异常也被抛到了socketRead上。错误不会触及日志,我们将其单独视为孤立的问题,只在启动问题开始并设置了SocketException断点时才找到原因:

代码语言:javascript
复制
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  

关于论点:

代码语言:javascript
复制
arg0  FileDescriptor  (id=499)  
  fd  1097  
  useCount  AtomicInteger  (id=503) 
    value 2 
arg1  (id=502)
arg2  0 
arg3  8192  
arg4  20000 

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

应用配置

应用程序的细节过于复杂,无法详细说明,但我有预感这可能与先前的绑定有关,因此我至少会列出机器上的侦听端口:

代码语言:javascript
复制
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 10.7.x和10.8.0至1.8.3受到影响
  • 文件描述符限制-从5000增加到10000
  • 在主以太网接口上完全禁用IPv6
  • 设置断点,并删除受SocketException影响的第一个上下文(它们是对web服务的传出HTTP调用)。没有变化
  • 配置/etc/hosts,使机器主机名解析为本地主机,并配置JVM选项以选择IPv4而不喜欢IPv6地址(这个答案:https://stackoverflow.com/a/16318860/364206)

对于那些对主机配置感兴趣的人来说,这和默认配置是一样的。我可以在Fusion /一个10.8的干净安装上再现这一点:

代码语言:javascript
复制
##
# 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 for SocksSocketImpl(PlainSocketImpl).socketAccept(SocketImpl),没有什么不寻常的地方。

代码语言:javascript
复制
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代码调查

考虑到通用消息,我假设必须从EINVAL JNI代码中的一个系统调用返回一个socketAccept错误,因此我跟踪了导致异常的系统调用;没有从任何系统调用返回EINVAL。因此,我在OpenJDK源代码中查找socketAccept代码中设置并抛出EINVAL的条件,但我也找不到任何将errno设置为EINVAL的代码,也找不到以使用默认错误消息的方式调用NET_ThrowByNameWithLastErrorNET_ThrowCurrentNET_ThrowNew的代码。

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

代码语言:javascript
复制
 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中接受循环顶部的超时处理代码中,但我找不到NET_Timeouterrno设置为EINVAL并导致抛出这个SocketException的任何情况。我指的是这段代码;我假设jdk7u分支在大部分情况下都是Oracle中的工具:

  • http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/d4bf5c15837c/src/solaris/native/java/net/PlainSocketImpl.c
  • close.c
  • md.c

帮助!

在Mac上,我找不到任何外部世界受到这个问题影响的人,但是这里的几乎每个人都受到影响。必须有一些应用程序配置,但我已经用尽了所有可以找到根本原因的途径。

对于故障排除或对可能的原因的洞察力,我们将不胜感激。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-05-03 06:20:21

你试过打开JNI调试-Xcheck:jni吗?有趣的是,Oracle文档使用PlainSocketImpl.socketAccept错误作为何时使用该错误的示例。

还要注意的是,Bug 7131399的含义是JNI在大多数平台上使用poll(),而在Mac上使用select(),这是因为Mac上的poll()存在问题。所以也许select()也坏了。如果"ndfs大于FD_SETSIZE并且没有定义_DARWIN_UNLIMITED_SELECT“,select()将返回EINVAL。FD_SETSIZE是1024,听起来好像有大量的应用程序在加载,所以可能所有这些都是一次等待更多的1024个FDs。

要获得额外的学分,请查看相关的(据说是固定的) Java错误实际上是否固定在您的机器上。bug报告有指向测试用例的指针。

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

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

这个问题可以用以下代码再现:

代码语言:javascript
复制
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 7u 60解决了这个问题:

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

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

票数 21
EN

Stack Overflow用户

发布于 2013-05-01 06:55:56

我遇到了完全相同的问题(对于Tomcat7),当我在Eclipse中运行tomcat时,我似乎需要选择“发布模块上下文来分离XML文件”选项。你试过了吗?

票数 1
EN

Stack Overflow用户

发布于 2014-05-15 22:14:51

使用修补程序获取OpenJDK:

2014.dmg

为我工作!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16191236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档