linux上TCP connection timeout问题解决办法

 linux上TCP connection timeout问题解决办法

最近在产线上经常出现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的情况,一切皆清楚了。

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

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

原创文章,作者:IUXYP,如若转载,请注明出处:http://www.wangzhanshi.com/n/8235.html

(0)
IUXYP的头像IUXYP
上一篇 2025年1月1日 16:35:01
下一篇 2025年1月1日 16:35:05

相关推荐

  • Linux下文件的切分与合并的简单方法介绍

    linux下文件分割可以通过split命令来实现,可以将一个大文件拆分成指定大小的多个文件,并且拆分速度非常的快,可以指定按行数分割和安大小分割两种模式。Linux下文件合并可以通…

    Linux 2025年1月1日
  • Linux开机启动过程详解

    计算机开机是一个神秘的过程。我们只是按了开机键,就看到屏幕上的进度条或者一行行的输出,直到我们到达登录界面。然而,计算机开机又是个异常脆弱的过程,我们满心期望的登录界面可能并不会出…

    Linux 2025年1月1日
  • Linux下动态链接库加载路径及搜索路径问题

    引子 近日,服务器迁移后,偷懒未重新编译nginx的,直接./nginx启动,结果遇到如下问题:“error while loading shared libraries”这是是因…

    Linux 2025年1月1日
  • Linux网络相关配置文件

    Linux网络相关配置文件 一 网络参数与配置文件对应关系   所需要的网络参数 主要配置文件命名 重要参数 IP Netmask DHCP Gateway等 /etc/sysco…

    Linux 2025年1月1日
  • linux如何修改用户密码

    一、概述 linux修改用户命名有两种方式 1、使用chpasswd通过用户输入'用户名:密码'来更改一组用户的密码,这种为明问修改密码,查看历史命令是可以看到…

    2024年12月17日
  • Linux 中清空或删除大文件内容的五种方法

    在 linux 终端下处理文件时,有时我们想直接清空文件的内容但又不必使用任何linux命令行编辑器 去打开这些文件。那怎样才能达到这个目的呢?在这篇文章中,我们将介绍几种借助一些…

    2025年1月1日
  • Linux如何使用HTTP进行远程系统监控

    简介 HTTP协议概述 HTTP协议是 超文本传输协议 ,基于TCP/IP通信协议,用于从万维网服务器传输数据到本地浏览器。 它的工作原理基于 客户端-服务器架构 ,浏览器作为客户…

    2024年12月17日
  • Linux 常用命令挂载命令详解

    查询与自动挂载 mount 查询系统中已经挂载的设备 mount -a 依据配置文件 /etc/fstab的内容,自动挂载 挂载命令格式 mount [-t 文件系统] [-o 特…

    2025年1月1日
  • 详解Linux上svn命令行批量操作

    详解Linux上svn命令行批量操作   虽然说git很好,大多数时候我也是使用git,但是有时候因为一些原因,不得不使用svn,而在linux上使用svn是没有像windows上…

    Linux 2025年1月1日
  • Linux expect实现自动登录脚本实例代码

    expect expect可以让我们实现自动登录远程机器,并且可以实现自动远程执行命令。当然若是使用不带密码的密钥验证同样可以实现自动登录和自动远程执行命令。但当不能使用密钥验证的…

    Linux 2025年1月1日

发表回复

登录后才能评论