文档章节

tcp短连接TIME_WAIT问题解决方法大全

zhangyujsj
 zhangyujsj
发布于 2016/10/12 15:05
字数 1737
阅读 161
收藏 2

tcp连接是网络编程中最基础的概念,基于不同的使用场景,我们一般区分为“长连接”和“短连接”,
长短连接的优点和缺点这里就不详细展开了,有心的同学直接去google查询,本文主要关注如何解决tcp短连接的TIME_WAIT问题。


短连接最大的优点是方便,特别是脚本语言,由于执行完毕后脚本语言的进程就结束了,基本上都是用短连接。
但短连接最大的缺点是将占用大量的系统资源,例如:本地端口、socket句柄。
导致这个问题的原因其实很简单:tcp协议层并没有长短连接的概念,因此不管长连接还是短连接,连接建立->数据传输->连接关闭的流程和处理都是一样的。


正常的TCP客户端连接在关闭后,会进入一个TIME_WAIT的状态,持续的时间一般在1~4分钟,对于连接数不高的场景,1~4分钟其实并不长,对系统也不会有什么影响,
但如果短时间内(例如1s内)进行大量的短连接,则可能出现这样一种情况:客户端所在的操作系统的socket端口和句柄被用尽,系统无法再发起新的连接!


举例来说:假设每秒建立了1000个短连接(Web场景下是很常见的,例如每个请求都去访问memcached),假设TIME_WAIT的时间是1分钟,则1分钟内需要建立6W个短连接,
由于TIME_WAIT时间是1分钟,这些短连接1分钟内都处于TIME_WAIT状态,都不会释放,而Linux默认的本地端口范围配置是:net.ipv4.ip_local_port_range = 32768    61000
不到3W,因此这种情况下新的请求由于没有本地端口就不能建立了。


可以通过如下方式来解决这个问题:
1)可以改为长连接,但代价较大,长连接太多会导致服务器性能问题,而且PHP等脚本语言,需要通过proxy之类的软件才能实现长连接;
2)修改ipv4.ip_local_port_range,增大可用端口范围,但只能缓解问题,不能根本解决问题;
3)客户端程序中设置socket的SO_LINGER选项;
4)客户端机器打开tcp_tw_recycle和tcp_timestamps选项;
5)客户端机器打开tcp_tw_reuse和tcp_timestamps选项;
6)客户端机器设置tcp_max_tw_buckets为一个很小的值;


在解决php连接Memcached的短连接问题过程中,我们主要验证了3)4)5)6)几种方法,采取的是基本功能验证和代码验证,并没有进行性能压力测试验证,
因此实际应用的时候需要注意观察业务运行情况,发现丢包、断连、无法连接等现象时,需要关注是否是因为这些选项导致的


虽然这几种方法都可以通过google查询到相关信息,但这些信息大部分都是泛泛而谈,而且绝大部分都是人云亦云,没有很大参考价值。
我们在定位和处理这些问题过程中,遇到一些疑惑和困难,也花费了一些时间去定位和解决,以下就是相关的经验总结。

 

 

SO_LINGER是一个socket选项,通过setsockopt API进行设置,使用起来比较简单,但其实现机制比较复杂,且字面意思上比较难理解。
解释最清楚的当属《Unix网络编程卷1》中的说明(7.5章节),这里简单摘录:
SO_LINGER的值用如下数据结构表示:
struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */

};

 

其取值和处理如下:
1、设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;
2、设置 l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,
   而不是通常的四分组终止序列,这避免了TIME_WAIT状态;
3、设置 l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。
   如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)
   或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。
   close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成。
   
第一种情况其实和不设置没有区别,第二种情况可以用于避免TIME_WAIT状态,但在Linux上测试的时候,并未发现发送了RST选项,而是正常进行了四步关闭流程,
初步推断是“只有在丢弃数据的时候才发送RST”,如果没有丢弃数据,则走正常的关闭流程。
查看Linux源码,确实有这么一段注释和源码:
=====linux-2.6.37 net/ipv4/tcp.c 1915=====
/* As outlined in RFC 2525, section 2.17, we send a RST here because
* data was lost. To witness the awful effects of the old behavior of
* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
* GET in an FTP client, suspend the process, wait for the client to
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, sk->sk_allocation);

另外,从原理上来说,这个选项有一定的危险性,可能导致丢数据,使用的时候要小心一些,但我们在实测libmemcached的过程中,没有发现此类现象,
应该是和libmemcached的通讯协议设置有关,也可能是我们的压力不够大,不会出现这种情况。


第三种情况其实就是第一种和第二种的折中处理,且当socket为非阻塞的场景下是没有作用的。
对于应对短连接导致的大量TIME_WAIT连接问题,个人认为第二种处理是最优的选择,libmemcached就是采用这种方式,
从实测情况来看,打开这个选项后,TIME_WAIT连接数为0,且不受网络组网(例如是否虚拟机等)的影响。

 

 

 

 

 

本文转载自:http://blog.csdn.net/yunhua_lee/article/details/8146837

共有 人打赏支持
zhangyujsj
粉丝 24
博文 358
码字总数 224241
作品 0
广州
私信 提问
再叙TIME_WAIT

之所以起这样一个题目是因为很久以前我曾经写过一篇介绍TIMEWAIT的文章,不过当时基本属于浅尝辄止,并没深入说明问题的来龙去脉,碰巧这段时间反复被别人问到相关的问题,让我觉得有必要全面...

银月光海
2016/05/06
27
0
Socket 连接问题之大量 TIME_WAIT

简评:最近项目就出现了大量短连接导致建立新连接超时问题,最后是通过维护长连接解决的。 代理或者服务器设备都有端口限制,如果使用 TCP 连接,连接数量达到端口限制,在这种情况下,将不能...

极小光
2018/12/21
0
0
mysql 大量time wait 解决办法

今天早上一上班,有同事就反映公司好几个网站都打不开,登陆数据库 服务器(windows),发现很卡,于是重启了下服务器,进入系统后,没过一会问题依旧,查看了下系统进程,发现mysql占用率达到9...

mj4738
2011/11/03
0
0
Tcp连接出现大量ESTABLISHED连接解决方法

TCP状态转移要点 TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不 会被释放。网络服务器...

qianghong000
2017/11/09
0
0
TCP/IP TIME_WAIT状态原理

TIMEWAIT状态原理 ---------------------------- 通信双方建立TCP连接后,主动关闭连接的一方就会进入TIMEWAIT状态。 客户端主动关闭连接时,会发送最后一个ack后,然后会进入TIMEWAIT状态,...

2k10
2015/09/21
79
0

没有更多内容

加载失败,请刷新页面

加载更多

编码规范

4.、编码时的一些建议 1、尽量指定类、方法的final修饰符——虚拟机会想办法内联所有的final方法来减少方法执行时创建栈帧的数量,从而降低栈溢出的风险 2、尽量重用对象——重复new对象会增...

呵呵哒灬
58分钟前
2
0
第一个docker化的java应用

Docker 思想 集装箱 标准化:运输方式/存储方式/API 接口 隔离

BeanHo
58分钟前
1
0
数据库技术-Mysql主从复制与数据备份

数据库技术-Mysql 主从复制的原理: MySQL中数据复制的基础是二进制日志文件(binary log file)。一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以“事件”...

须臾之余
昨天
14
0
Git远程仓库——GitHub的使用(一)

Git远程仓库——GitHub的使用(一) 一 、 Git远程仓库 由于你的本地仓库和GitHub仓库之间的传输是通过SSH加密的,所以需要一下设置: 步骤一、 创建SSH key 在用户主目录下,看看有没有.ss...

lwenhao
昨天
4
0
SpringBoot 整合

springBoot 整合模板引擎 SpringBoot 整合Mybatis SpringBoot 整合redis SpringBoot 整合定时任务 SpringBoot 整合拦截器...

细节探索者
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部