linux上TCP connection timeout问题解决办法

2019-01-17 00:12:14于海丽

同时设置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; }