关闭

linux上TCP connection timeout的原因查找

19998人阅读 评论(0) 收藏 举报
分类:

最近在产线上经常出现connection timeout的问题,先看看java 中关于connection timeout 的异常如何产生

JAVA中的timeout

java.net.SocketTimeoutException: connect timed out
客户端异常:connect timed out
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)

我们能经常看到的connect timed out异常产生,看一下java 是如何生成这个异常

plainsocketimpl.c 中

while (1) {
                jlong newTime;
#ifndef USE_SELECT
                {
                    struct pollfd pfd;
                    pfd.fd = fd;
                    pfd.events = POLLOUT;

                    errno = 0;
                    connect_rv = NET_Poll(&pfd, 1, timeout);
                }
#else
                {
                    fd_set wr, ex;
                    struct timeval t;

                    t.tv_sec = timeout / 1000;
                    t.tv_usec = (timeout % 1000) * 1000;

                    FD_ZERO(&wr);
                    FD_SET(fd, &wr);
                    FD_ZERO(&ex);
                    FD_SET(fd, &ex);

                    errno = 0;
                    connect_rv = NET_Select(fd+1, 0, &wr, &ex, &t);
                }
#endif

                if (connect_rv >= 0) {
                    break;
                }
                if (errno != EINTR) {
                    break;
                }

                /*
                 * The poll was interrupted so adjust timeout and
                 * restart
                 */
                newTime = JVM_CurrentTimeMillis(env, 0);
                timeout -= (newTime - prevTime);
                if (timeout <= 0) {
                    connect_rv = 0;
                    break;
                }
                prevTime = newTime;

            } /* while */

            if (connect_rv == 0) {
                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
                            "connect timed out");

                /*
                 * Timeout out but connection may still be established.
                 * At the high level it should be closed immediately but
                 * just in case we make the socket blocking again and
                 * shutdown input & output.
                 */
                SET_BLOCKING(fd);
                JVM_SocketShutdown(fd, 2);
                return;
            }

这里可以看到在做connect的时候,是调用 NET_Poll 或者 NET_Select, 在linux 上就是使用 poll/select

当发生timeout的时候connect_rv=0  ,这里有个注意点虽然在poll/select 是传入timeout的时间,但是这是会被打断的,connect_rv返回的值为-1 ,所以jvm里面重新计算了timeout , 确保timeout 的时间片已经运行完了,才推出循环。

newTime = JVM_CurrentTimeMillis(env, 0);
                timeout -= (newTime - prevTime);
                if (timeout <= 0) {
                    connect_rv = 0;
                    break;
                }

同时设置connect_rv 为0, 也是下面只有当connect_rv为0的时候才抛出connect timeout


什么是connect timeout ? 

也就是client 发出 syn 包,server端在你指定的时间内没有回复ack,poll/select 返回0


server 端为什么没有回复ack, 因为syn包的回复是内核层的,要么网络层丢包,要么就是内核层back_log的queue满了,关于backlog在本片中就不详细描述了。

当时查看产线上的连接最高能到1000多,同时查看了backlog 的queue的大小

cat /proc/sys/net/ipv4/tcp_max_syn_backlog

有8192 在产线上没有这么多的客户端的连接,不可能backlog queue会满

虽然syn_backlog 的设置是8192 但并不代表服务器启动的时候设置成了8192,所以必须查这个端口所设置的backlog大小

ss -lt

看到Send-Q在8080端口是128 ,原来在服务器端启动listen 的时候设置了128的backlog 

查看tomcat 的配置,默认bio的设置

<Connector executor="tomcatThreadPool"
   			port="8080" 
    			protocol="HTTP/1.1"
               		acceptCount="5000"
           			connectionTimeout="25000"
               		maxHttpHeaderSize="8192"
               		useBodyEncodingForURI="true"
               		enableLookups="false"  
               		redirectPort="8443" 
               		URIEncoding="UTF-8" 
               		maxThreads="500"
               		maxKeepAliveRequests="1000"
               		keepAliveTimeout="30000"
				/>

产线上已经设置了acceptCount, 默认是100 但是这里设置了是5000 ,这与通过ss看到的send-q的结果严重不符合

通过内核代码分析,发现原来内核参数不仅仅是通过tcp_max_syn_backlog控制,同时也受somaxconn控制

查看

cat /proc/sys/net/core/somaxconn
发现值是128, OK 原因找到了,修改/etc/sysctl.conf 添加

net.core.somaxconn = 8192

sysctl -f /etc/sysctl.conf 重新加载一下,这样就能改变全局了


问题:是1000多个连接,500个工作线程,因为backlog的大小是受socket.accept控制的,我们通常境况下会单独起一个线程去serversocket.accept(),而当前server的load并不高,不因该会出现back_log queue出现满的情况,更何况只有1000多个连接,代码就是真相,查看tomcat的源码。

原来accptor 线程在accept 之前,会去countUpOrWaitConnection 发现接受到的的socket数目大于设置的work线程数目的时候,会停止accept.

   <strong>countUpOrAwaitConnection</strong>();

                    Socket socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSocketFactory.acceptSocket(serverSocket);
                    } catch (IOException ioe) {
                        countDownConnection();
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }

也就是说当并发超过628个连接以上,就有可能出现backlog queue满的情况,而出现connect timeout的情况,一切皆清楚了。





3
0
查看评论

Linux recv返回-1 errno=ETIMEDOUT(Connection timed out) .

关于errno值的定义在errno.h中 [cpp:nogutter] view plaincopy #ifndef _I386_ERRNO_H   #define _I386_ERRNO_H&#...
  • u010419967
  • u010419967
  • 2014-04-24 12:29
  • 4263

Linux设置socket连接超时

Linux设置socket连接超时(异步连接)   转载▼ 标签:  linux   socket   connect   超时   it 分类: Li...
  • cuiyifang
  • cuiyifang
  • 2013-01-26 17:21
  • 6203

Linux下的socket编程实践(五)设置套接字I/O超时的方案

(一)使用alarm 函数设置超时 #include unsigned int alarm(unsigned int seconds); 它的主要功能是设置信号传送闹钟。信号SIGALRM在经过seconds指定的秒数后传送给目前的进程,如果在定时未完成的时间内再次调用了alarm函数,则...
  • NK_test
  • NK_test
  • 2015-10-11 19:57
  • 3282

linux网络编程之socket(十一):套接字I/O超时设置方法和用select实现超时

注:如无特殊说明,sockfd 原始状态都是阻塞的。 一、使用alarm 函数设置超时  C++ Code  1 2 3 4 5 6 7 8 9 10 11 12 13 voi...
  • imxiangzi
  • imxiangzi
  • 2016-01-08 00:14
  • 1284

linux socket套接字超时之setsockopt

超时一些注意事项. 这里只是记录测试的一些结果,仅供参考和探讨.不附加测试代码了. 测试环境:系统debian 6,内核版本:2.6.32-5-686 设置/获取超时代码 struct timeval ti; ti.tv_sec=5; ti.tv_usec...
  • cdhql
  • cdhql
  • 2014-12-11 16:37
  • 8391

linux下socket connect超时设置

今天发现自己的系统存在很严重缺陷,当前台关闭的时候后台就无法正常工作,原因很好定位,后台的socket连接超时时间过长,系统默认时间好像是75秒,于是找资料,根据下边文章中的内容解决了,把超时时间设为5秒后,感觉好多了。看来还有好多东西需要慢慢挖掘阿! 如何设置socket的Connect...
  • liangzhao_jay
  • liangzhao_jay
  • 2016-01-20 10:34
  • 4264

linux socket 设置连接超时的方法

1.alarm方法 http://hi.baidu.com/ppln/blog/item/0523d3090731689d0a7b8200.html #include #include #include #include #include #include #include #in...
  • infelt
  • infelt
  • 2014-06-12 09:42
  • 2063

TCP-IP详解卷1-21:TCP的超时与重传(Timeout and Retransmission)

超时与重传
  • chpdirector84
  • chpdirector84
  • 2010-11-24 23:14
  • 18101

使用TCP Keep-alive与TCP_USER_TIMEOUT机制判断通信对端是否存活

最近在做RDP协议代理的时候被测试提了一个Bug,Bug说的是当通信中的服务器网线被拔了以后,代理程序不能检测到对端已经不可用,不能正常退出。我的第一反应是调用send的时候为什么没有返回-1呢?接下来的测试让我重新认识了send。 正常通信的情况下,send函数发送成功会返回发送数据的字节数。当...
  • nui111
  • nui111
  • 2014-12-01 20:32
  • 2433

TCP/IP详解--如何处理TIME_WAIT状态

netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}' 会得到类似下面的结果,具体数字会有所不同: LAST_ACK 1 SYN_REC...
  • yusiguyuan
  • yusiguyuan
  • 2014-04-04 11:42
  • 3941
    个人资料
    • 访问:499994次
    • 积分:5446
    • 等级:
    • 排名:第5866名
    • 原创:100篇
    • 转载:3篇
    • 译文:0篇
    • 评论:73条
    最新评论