[英]Tomcat 7 throwing frequent java.net.SocketException: Connection reset
[英]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
。 我一直都配置了這個選項 5000
增加到10000
/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
由於問題的明顯時間敏感性,設置斷點以解決問題導致它不會發生。 根據評論中的要求,我還為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處理器線程重復。
給定通用消息,我假設必須從socketAccept JNI代碼中的一個系統調用返回EINVAL
錯誤,因此我跟蹤導致異常的系統調用; 任何系統調用都沒有返回EINVAL
。 所以,我去OpenJDK源尋找socketAccept代碼中的條件,該代碼將設置然后拋出一個EINVAL
,但我也找不到任何將errno
為EINVAL
代碼,或者調用NET_ThrowByNameWithLastError
, NET_ThrowCurrent
或NET_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_Timeout
將errno
為EINVAL
任何情況,並導致拋出此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文件”選項。 你已經試過了嗎?
我在另一個環境中一直在與這個問題作斗爭。 來自不同來源的解決方案如下所示:
(EWD-MacBook-Pro.local是我的機器名稱)
和
祝好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.