服务器之家:专注于服务器技术及软件下载分享
分类导航

Linux|Centos|Ubuntu|系统进程|Fedora|注册表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服务器之家 - 服务器系统 - Linux - linux上TCP connection timeout问题解决办法

linux上TCP connection timeout问题解决办法

2022-01-10 16:59raintungli Linux

这篇文章主要介绍了 linux上TCP connection timeout问题解决办法的相关资料,需要的朋友可以参考下

 linux上TCP connection timeout问题解决办法

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

JAVA中的timeout

?
1
2
3
4
5
6
7
8
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 中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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 的时间片已经运行完了,才推出循环。

?
1
2
3
4
5
6
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的大小

?
1
cat /proc/sys/net/ipv4/tcp_max_syn_backlog

有8192 在产线上没有这么多的客户端的连接,不可能backlog queue会满,虽然syn_backlog 的设置是8192 但并不代表服务器启动的时候设置成了8192,所以必须查这个端口所设置的backlog大小

?
1
ss -lt

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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控制
查看

?
1
cat /proc/sys/net/core/somaxconn

发现值是128, OK 原因找到了,修改/etc/sysctl.conf 添加

?
1
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.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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的情况,一切皆清楚了。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

原文链接:http://blog.csdn.net/raintungli/article/details/37879907

延伸 · 阅读

精彩推荐
  • Linuxlinux中rmdir命令使用详解(删除空目录)

    linux中rmdir命令使用详解(删除空目录)

    今天学习一下linux中命令: rmdir命令。rmdir是常用的命令,该命令的功能是删除空目录,一个目录被删除之前必须是空的 ...

    linux命令大全5372019-11-19
  • Linux手把手教您在 Linux 上使用 GPG 加解密文件

    手把手教您在 Linux 上使用 GPG 加解密文件

    在本教程中,我将告诉你如何用 GPG 加密和解密文件。这是一个简单的教程,你可以在你的 Linux 系统上尝试所有的练习。这将帮助你练习 GPG 命令,并在你...

    Linux中国6962021-12-15
  • LinuxLinux上设置用户通过SFTP访问目录的权限的方法

    Linux上设置用户通过SFTP访问目录的权限的方法

    这篇文章主要介绍了Linux上设置用户通过SFTP访问目录的权限的方法,SFTP可以理解为使用SSH协议进行FTP传输的协议,因而同时要对OpenSSH进行相关设置,需要的朋...

    OSChina10022019-06-19
  • LinuxLinux常用的日志文件和常用命令

    Linux常用的日志文件和常用命令

    成功地管理任何系统的关键之一,是要知道系统中正在发生什么事。 Linux 中提供了异常日志,并且日志的细节是可配置的。Linux 日志都以明文形式存储,所...

    Linux教程网2632020-04-18
  • Linux确保Linux系统安全的前提条件 漏洞防护

    确保Linux系统安全的前提条件 漏洞防护

    Linux 作为开放式的操作系统受到很多程序员的喜爱,很多高级程序员都喜欢编写Linux操作系统的相关软件。这使得Linux操作系统有着丰富的软件支持,还有无...

    Linux之家2642020-04-11
  • LinuxLinux中环境变量配置的步骤详解

    Linux中环境变量配置的步骤详解

    Linux中环境变量包括系统级和用户级,系统级的环境变量是每个登录到系统的用户都要读取的系统变量,而用户级的环境变量则是该用户使用系统时加载的...

    Myths7882022-02-10
  • Linux详解Linux系统下PXE服务器的部署过程

    详解Linux系统下PXE服务器的部署过程

    这篇文章主要介绍了Linux系统下PXE服务器的部署过程,包括对PXE的API架构作了一个基本的简介,需要的朋友可以参考下...

    运维之道9812019-07-04
  • LinuxLinux lnmp下无法使用mail发邮件的两种解决方法

    Linux lnmp下无法使用mail发邮件的两种解决方法

    在配置了lnmp环境后,出现了mail函数不能发送邮件的问题,其实有两种方法,一是使用sendmail组件,而是使用postfix。下面为大家一一介绍下 ...

    Linux之家4042019-09-17