簡體   English   中英

由於Mac OS X上的“java.net.SocketException Invalid argument”,Tomcat啟動失敗

[英]Tomcat startup fails due to 'java.net.SocketException Invalid argument' on Mac OS X

我們有一個在Tomcat 6上運行的應用程序(准確地說是6.0.35.0),由於Catalina.await方法中的socketAccept調用拋出SocketException,我們在Mac OS上的大多數工程師都遇到啟動Tomcat的問題:

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秒。 我們可以通過禁用開發期間不需要的一些非強制性上下文來減少啟動時間來緩解問題,但我更願意找到根本原因。

應用配置

該應用程序的細節太復雜,無法詳細說明,但我有一個預感,這可能與早期的綁定有關,所以我至少會列出我的機器上的監聽端口:

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代碼調查

由於問題的明顯時間敏感性,設置斷點以解決問題導致它不會發生。 根據評論中的要求,我還為SocksSocketImpl(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使我確信觸發器可能是一些執行基於套接字的操作的計划任務,然后影響其他套接字操作。

這並沒有解釋為什么這會影響幾個線程,無論我們做什么導致這種情況,神秘的SocketExceptions不應該從本機代碼冒出來並在多個線程上同時導致這些異常 - 也就是說,兩個線程進行傳出Web服務調用,Tomcat等待調用,以及多個TP處理器線程重復。

JNI代碼調查

給定通用消息,我假設必須從socketAccept JNI代碼中的一個系統調用返回EINVAL錯誤,因此我跟蹤導致異常的系統調用; 任何系統調用都沒有返回EINVAL 所以,我去OpenJDK源尋找socketAccept代碼中的條件,該代碼將設置然后拋出一個EINVAL ,但我也找不到任何將errnoEINVAL代碼,或者調用NET_ThrowByNameWithLastErrorNET_ThrowCurrentNET_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_TimeouterrnoEINVAL任何情況,並導致拋出此SocketException。 我指的是這段代碼; 我假設jdk7u分支大部分是Oracle JDK中的內容:

救命!

我無法在Mac OS上找到受此特定問題影響的外界人士,但幾乎每個人都受到影響。 必須有一些應用程序配置有所貢獻,但我已經用盡了我能想到的每個途徑來找到根本原因。

有關故障排除或對可能原因的見解的指示將非常感激。

您是否嘗試過使用-Xcheck:jni 打開JNI調試 有趣的是, Oracle文檔使用PlainSocketImpl.socketAccept錯誤作為何時使用它的示例。

另請注意, Bug 7131399的含義是JNI在大多數平台上使用poll() ,但由於Mac上的poll()問題而在Mac OS上使用select() 所以也許select()也被打破了。 進一步挖掘,如果“ndfs大於FD_SETSIZE且未定義_DARWIN_UNLIMITED_SELECT,則select()將返回EINVAL”。 FD_SETSIZE是1024,聽起來你有大量的應用程序加載,所以也許所有過濾器一直在等待更多的1024個FD。

要獲得額外的功勞,請查看您的計算機上是否已修復相關的(據稱已修復的)Java錯誤 錯誤報告指向測試用例。


感謝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秒后關閉了文件句柄,這解釋了為什么設置斷點可以防止問題發生。

我有完全相同的問題(使用Tomcat7),當我在Eclipse中運行tomcat時,似乎對我有用的是勾選“發布模塊上下文以分離XML文件”選項。 你已經試過了嗎?

我在另一個環境中一直在與這個問題作斗爭。 來自不同來源的解決方案如下所示:

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

(EWD-MacBook-Pro.local是我的機器名稱)

  • 設置系統屬性:
    • java.net.preferIPv4Stack => true
    • java.net.preferIPv6Addresses => false

祝好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM