Java 为什么当webservice停止工作时,我看到很多套接字处于关闭等待状态?

Java 为什么当webservice停止工作时,我看到很多套接字处于关闭等待状态?,java,tomcat,tcp,jetty,load-balancing,Java,Tomcat,Tcp,Jetty,Load Balancing,我在Jetty上运行的java Web服务在几个小时后崩溃,调查表明许多套接字处于关闭等待状态。当它工作正常时,似乎没有处于关闭等待状态的插座,但当它出错时,会有负载 我找到了这个 CLOSE-WAIT(关闭等待):本地端点已接收到连接终止请求并予以确认,例如,已执行被动关闭,本地端点需要执行主动关闭以离开此状态 在我的服务器上使用netstat时,我看到一个tcp套接字列表处于关闭等待状态,本地地址是我的服务器,外部地址是我的负载平衡器机器。因此,我假设这意味着客户端(负载平衡器)刚刚以某种不

我在Jetty上运行的java Web服务在几个小时后崩溃,调查表明许多套接字处于关闭等待状态。当它工作正常时,似乎没有处于关闭等待状态的插座,但当它出错时,会有负载

我找到了这个

CLOSE-WAIT(关闭等待):本地端点已接收到连接终止请求并予以确认,例如,已执行被动关闭,本地端点需要执行主动关闭以离开此状态

在我的服务器上使用netstat时,我看到一个tcp套接字列表处于关闭等待状态,本地地址是我的服务器,外部地址是我的负载平衡器机器。因此,我假设这意味着客户端(负载平衡器)刚刚以某种不正确的方式终止了其端的连接,而我的服务器没有正确地关闭其端的连接

但是我该怎么做呢,我的Java代码不处理低级套接字


或者负载平衡器终止连接是因为我的服务器在代码中出错而导致的早期问题。

负载平衡器是否仍在运行?尝试停止负载平衡器,看看这是不是服务器的问题。

听起来像是Jetty或JVM中的一个bug,也许这个解决方法适合您:

将以下行添加到/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

或者重新启动

这可能意味着您没有清理传入的连接。确保在每个事务结束时关闭套接字。(最好在服务器代码开始时关闭连接,这样即使出现服务器端异常也可以关闭连接。)

我怀疑这可能是导致服务器代码中出现长时间或无限循环/无限等待的原因,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客户端,
netstat
将显示服务器端套接字仍处于
CLOSE\u WAIT
-状态(我还可以看到FIN_WAIT2-state中的客户端套接字有一段时间,但它会消失):

服务器端接受的套接字陷入关闭等待状态。如果我检查进程的线程堆栈,我可以看到线程在do…while-循环中等待:

~$ 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...>

如果有很多线程在运行,则更容易发现它们。

我们的项目中也有同样的问题。我不确定这是否是您的情况,但可能会有所帮助

原因是大量的请求是由具有同步块的业务逻辑处理的。因此,当客户端发送数据包以断开连接时,绑定到此套接字的线程正忙着,等待监视器

日志显示org.eclipse.jetty.io.WriteFlusher在write方法中的异常:

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]
对于org.eclipse.jetty.server.HttpOutput at close方法,我认为close步骤的异常是套接字close\u 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。正确的解决方案(同样在我们的案例中)是代码重构


因此,我的建议是仔细阅读Jetty的调试级日志,以发现异常,并使用VisualVM分析应用程序性能。原因可能是性能瓶颈(同步块?)。

我遇到了类似的问题,虽然罪魁祸首代码可能不同,但症状不同 1) 服务器(Jetty)正在运行,但尚未处理请求 2) 没有异常负载/异常 3) 那里有太多的近距离连接


这表明服务器中的所有工作线程都卡在某个地方。Jstack线程转储显示我们所有的工作线程都卡在ApacheHttpClient对象中。(由于响应对象未关闭),并且由于所有线程都在无限期等待,因此没有线程可用于处理传入请求

标记为duplicate的问题看起来类似,但解决方案没有帮助,因为它表明问题出在客户端,但我们不能仅通过服务器控制客户端,因此我们需要一种方法,让服务器即使客户端出错也能应对。问题不在客户端,而在服务器,或者更确切地说,无论哪一端显示接近或等待@Kayaman并不是一个真正的复制品,因为另一个是关于具有这种情况的客户端的,并且有一个仅用于客户端的解决方案。@EJP哦,好吧,我不知道如何解决这个问题。我的servlet中有一个doGet(HttpServletRequest-request,HttpServletResponse-response)方法,其中许多方法都有response.redirect(),response.sendError()或更常见的PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter,response.getOutputStream(),CHARSET));作者:写(输出、结果、响应格式、isPretty);out.close();然后再回来。我不直接处理插座,所以我如何解决这个问题?我认为你必须向后因果。CLOSE_WAIT中的套接字是服务器崩溃的症状,而不是服务器崩溃的原因。只有发送FIN的客户端才能产生CLOSE_WAIT,如果它持续存在,则是服务器未能执行某些操作(即关闭套接字)造成的@DavidSchwartz是对的,这一切都是从后面到前面的。我认为问题出在负载平衡器上,但每个人都告诉我,这必须是我的服务器,因为CLOSE_WAIT在我的服务器上,因此问题出在我的服务器上,但如果负载平衡器不工作,可能会阻止服务器脱离CLOSE_WAIT连接。对更基本的http问题的回答可能对我有所帮助,客户机向服务器发送http请求,然后服务器发送响应。接下来会发生什么,当客户端接收到来自的响应时,是否隐式初始化关闭连接
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]
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]