我在Jetty上运行的java webservice在几个小时之后就会崩溃,调查显示许多套接字处于CLOSE_WAIT状态。虽然它工作正常但似乎没有CLOSE_WAIT状态的套接字,但是当它出错时会有负载。
我发现了definition
CLOSE-WAIT:本地端点已收到连接终止请求并确认它,例如已执行被动关闭,并且本地端点需要执行主动关闭才能离开此状态。
在我的服务器上使用netstat,我看到一个CLOSE_WAIT状态的tcp套接字列表,本地地址是我的服务器,外部地址是我的负载均衡器机器。所以我认为这意味着客户端(负载均衡器)刚刚以某种不正当的方式终止了连接,并且我的服务器没有正确地关闭它的连接。
但是我该怎么做,我的Java代码不处理低级套接字?
或者是负载均衡器终止连接,因为我的服务器在代码中出错了导致的早期问题。
答案 0 :(得分:6)
听起来像是Jetty或JVM中的错误,也许这种解决方法对您有用: http://www.tux.hk/index.php?entry=entry090521-111844
将以下行添加到/etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_intvl = 2
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_time = 1800
然后执行
sysctl -p
或重新启动
答案 1 :(得分:5)
我们的项目存在同样的问题。我不确定这是你的情况,但也许会有所帮助。
原因是业务逻辑使用synchronized块处理了大量请求。因此,当客户端发送数据包到drop连接时,绑定到此套接字的线程正忙,等待监视器。
日志在写入方法中显示org.eclipse.jetty.io.WriteFlusher的异常:
DEBUG org.eclipse.jetty.io.WriteFlusher - write - write exception
org.eclipse.jetty.io.EofException: null
at org.eclipse.jetty.io.ChannelEndPoint.flush
(ChannelEndPoint.java:192) ~[jetty-io-9.2.10.v20150310.jar:9.2.10.v20150310]
和close方法中的org.eclipse.jetty.server.HttpOutput。我认为近距离的例外是套接字的原因。 CLOSE_WAIT状态:
DEBUG org.eclipse.jetty.server.HttpOutput - close -
org.eclipse.jetty.io.EofException: null
at org.eclipse.jetty.server.HttpConnection$SendCallback.reset
(HttpConnection.java:622) ~[jetty-server-9.2.10.v20150310.jar:9.2.10.v20150310]
我们案例中的快速解决方案是增加idleTimeout。正确的解决方案(在我们的例子中)是代码重构。
所以我的建议是仔细阅读带有DEBUG级别的Jetty日志,以查找异常并使用VisualVM分析应用程序性能。也许原因是性能瓶颈(同步块?)。
答案 2 :(得分:4)
我怀疑这可能是导致服务器代码长时间或无限循环/无限等待的原因,Jetty根本没有机会关闭连接(除非有某种超时强行关闭套接字一段时间后)。请考虑以下示例:
public class TestSocketClosedWaitState
{
private static class SocketResponder implements Runnable
{
private final Socket socket;
//Using static variable to control the infinite/waiting loop for testing purposes, with while(true) Eclipse would complain of dead code in writer.close() -line
private static boolean infinite = true;
public SocketResponder(Socket socket)
{
this.socket = socket;
}
@Override
public void run()
{
try
{
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.write("Hello");
//Simulating slow response/getting stuck in an infinite loop/waiting something that never happens etc.
do
{
Thread.sleep(5000);
}
while(infinite);
writer.close(); //The socket will stay in CLOSE_WAIT from server side until this line is reached
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("DONE");
}
}
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = new ServerSocket(12345);
while(true)
{
Socket socket = serverSocket.accept();
Thread t = new Thread(new SocketResponder(socket));
t.start();
}
}
}
将infinite
- 变量设置为true,Printwriter(和底层套接字)永远不会因无限循环而关闭。如果我运行此命令并使用telnet连接到套接字,然后退出telnet-client,netstat
将显示服务器端口仍在CLOSE_WAIT
-state(我也可以看到客户端套接字)在FIN_WAIT2状态一段时间,但它会消失):
~$ netstat -anp | grep 12345
tcp6 0 0 :::12345 :::* LISTEN 6460/java
tcp6 1 0 ::1:12345 ::1:34606 CLOSE_WAIT 6460/java
服务器端接受的套接字卡在CLOSE_WAIT -state中。如果我检查进程的线程堆栈,我可以看到线程在do ... while -loop中等待:
~$ jstack 6460
<OTHER THREADS>
"Thread-0" prio=10 tid=0x00007f424013d800 nid=0x194f waiting on condition [0x00007f423c50e000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at TestSocketClosedWaitState$SocketResponder.run(TestSocketClosedWaitState.java:32)
at java.lang.Thread.run(Thread.java:701)
<OTHER THREADS...>
如果我将infinite
- 变量设置为false,并执行相同操作(连接客户端和断开连接),则会显示带有CLOSE_WAIT
-state的套接字,直到编写器关闭(关闭底层) socket),然后消失。如果编写器或套接字永远不会关闭,服务器端套接字将再次陷入CLOSED_WAIT
,即使线程终止(我不认为这应该发生在Jetty中,如果你的方法在某些方面返回点,Jetty可能应该关闭插座)。
所以,我建议你尝试找到罪魁祸首的步骤
jstack
从正在运行的Jetty进程进行线程转储,并尝试识别任何&#34;卡住&#34;线程Throwable
,所以这可能不是问题,但也许值得检查是否所有其他方法都失败您还可以在使用类似
之类的方式输入和退出方法时命名线程 String originalName = Thread.currentThread().getName();
Thread.currentThread().setName("myMethod");
//Your code...
Thread.currentThread().setName(originalName);
如果有很多线程正在运行,更容易发现它们。
答案 3 :(得分:0)
我遇到了类似的问题,而罪魁祸首代码可能有所不同,症状是 1)服务器(Jetty)正在运行但尚未处理请求 2)没有额外的普通负载/例外 3)有太多的CLOSE_WAIT连接。
这些表明服务器中的所有工作线程都被卡在某处。 Jstack Thread转储显示我们所有的工作线程都被困在apache HttpClient对象中。 (由于未关闭的响应对象),并且由于所有线程都在无限期等待,因此没有可用于处理传入请求的线程。
答案 4 :(得分:-1)
负载均衡器是否还在运行?尝试停止负载均衡器,看看这是不是服务器的问题。
答案 5 :(得分:-2)
这可能意味着您没有清理传入的连接。确保每次交易结束时套接字都关闭。 (最好在服务器代码开头附近的finally block内完成,这样即使发生服务器端异常,连接也会关闭。)