相关索引:https://blog.csdn.net/knowledgebao/article/details/84626184


目录

1,基础普及:

三次握手:

四次挥手

2,正文:那么服务端如何消除大量TCP短连接引发的TIME_WAIT呢?

1,编辑文件/etc/sysctl.conf(或者修改/proc/sys/net/ipv4下对应的文件),加入以下内容:

2,设置SO_LINGER属性(https://blog.csdn.net/yunhua_lee/article/details/8146837)。

3,扩展:

tcp_tw_recycle详解:

tcp_tw_reuse详解:

tcp_max_tw_buckets详解:

SO_LINGER详解:


1,基础普及:

#查看tcp各种状态的命名
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 50013
ESTABLISHED 27
SYN_RECV 1

其中可能出现:LISTEN、SYN-SEND、SYN-RECV、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、LAST_ACK、TIME_WAIT、CLOSED,具体详见下边的握手和挥手过程。

三次握手:

四次挥手

挥手为啥比握手多一次呢?因为握手被动一方回复的ACK和SYN同时发送,而挥手被动一方的ACK是单独发送的,具体握手和挥手过程参考https://blog.csdn.net/qzcsu/article/details/72861891

挥手状态说明:

  • FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方)
  • FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方)
  • CLOSE_WAIT:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。(被动方)
  • LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)
  • TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)
  • CLOSED: 表示连接中断。

上图中的MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

TIME_WAIT状态存在的原因以及为什么time_wait需要2*MSL等待时间?

若要TCP可靠地终止连接的两个方向 ( 全双工关闭 ) , 主动一方必须进入 TIME_WAIT状态。原因如下:

假设主动一方发送最终的 ACK 丢失 , 被动一方将重发 FIN , client 必须维护 TCP 状态信息以便可以重发最终的 ACK ,否则会导致两种情况的发生。

  • 情况一:如果主动一方断开了这个链接,则会触发RST发送给被动一方 ,导致被动一方认为发生错误。
  • 情况二:如果主动一方断开了这个链接,并且又建立了一个新的链接,并且新的链接的元素(源IP,目的IP,TCP,源端口,目的端口)刚好与之前的连接一样,这个FIN将以比较低但是确实可能的概率终止掉连接2,也就是说上一个链接的数据会延迟到下一个链接,并且影响下一个链接的正常使用,不一定是FIN,数据也可能延迟到下一个TCP链接中。(关于RST详见https://blog.csdn.net/knowledgebao/article/details/84644233)

2,正文:那么服务端如何消除大量TCP短连接引发的TIME_WAIT呢?

主动关闭socket的一方最终为time_wait,被动关闭的则为close_wait

1,编辑文件/etc/sysctl.conf(或者修改/proc/sys/net/ipv4下对应的文件),加入以下内容:

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30

然后执行 /sbin/sysctl -p 让参数生效。

  • net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
  • net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
  • net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
  • net.ipv4.tcp_fin_timeout = 30 表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。
  • net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。
  • net.ipv4.ip_local_port_range = 1024 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。
  • net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
  • net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默 认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。

2,设置SO_LINGER属性(https://blog.csdn.net/yunhua_lee/article/details/8146837)。


3,扩展:

tcp_tw_recycle详解:

定义:Enable fast recycling TIME-WAIT sockets. Default value is 0.

1)快速回收到底有多快?
局域网环境下,700ms就回收;
2)有的资料说只要打开tcp_tw_recycle即可,有的又说要tcp_timestamps同时打开,具体是哪个正确?
需要同时打开,但默认情况下tcp_timestamps就是打开的,所以会有人说只要打开tcp_tw_recycle即可;
3)为什么从虚拟机发起客户端连接时选项无效,非虚拟机连接就有效?
和网络组网有关系,无法获取对端信息时就不进行快速回收;

原因分析:计算快速回收的时间,等于 RTO * 3.5,回答第一个问题的关键是RTO(Retransmission Timeout)大概是多少
RFC中有关于RTO计算的详细规定,一共有三个:RFC-793、RFC-2988、RFC-6298,Linux的实现是参考RFC-2988。
=====linux-2.6.37 net/ipv4/tcp.c 126================
#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))
==========================================
这里的HZ是1s,因此可以得出RTO最大是120s,最小是200ms,对于局域网的机器来说,正常情况下RTO基本上就是200ms,因此3.5 RTO就是700ms

RFC1323中有如下一段描述(为什么NAT下有问题):An additional mechanism could be added to the TCP, a per-hostcache of the last timestamp received from any connection.This value could then be used in the PAWS mechanism to rejectold duplicate segments from earlier incarnations of theconnection, if the timestamp clock can be guaranteed to haveticked at least once since the old connection was open. Thiswould require that the TIME-WAIT delay plus the RTT togethermust be at least one tick of the sender’s timestamp clock.Such an extension is not part of the proposal of this RFC.

现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象:

shell> netstat -s | grep timestamp ... packets rejects in established connections because of timestamp

如果服务器身处NAT环境,安全起见,通常要禁止tcp_tw_recycle,至于TIME_WAIT连接过多的问题,可以通过激活tcp_tw_reuse来缓解。

进一步思考,既然必须同时激活tcp_timestamps和tcp_tw_recycle才会触发这种现象,那只要禁止tcp_timestamps,同时激活tcp_tw_recycle,就可以既避免NAT丢包问题,又降低TIME_WAIT连接数量。如果服务器并不依赖于RFC1323,那么这种方法应该也是可行的,不过最好多做测试,以防有其他的副作用。

tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。

tcp_tw_reuse详解:

Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0.
1)tcp_tw_reuse选项和tcp_timestamps选项也必须同时打开才能生效;
2)重用TIME_WAIT的条件是收到最后一个包后超过1s。

1. tw_reuse,tw_recycle 必须在客户端和服务端timestamps 开启时才管用(默认打开)

2. tw_reuse 只对客户端起作用,开启后客户端在1s内回收

3. tw_recycle 对客户端和服务器同时起作用,开启后在 3.5*RTO 内回收,RTO 200ms~ 120s 具体时间视网络状况。内网状况比tw_reuse 稍快,公网尤其移动网络大多要比tw_reuse 慢,优点就是能够回收服务端的TIME_WAIT数量

tcp_max_tw_buckets详解:

参考官方文档(http://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt),解释如下:
tcp_max_tw_buckets - INTEGER
Maximal number of timewait sockets held by system simultaneously. If this number is exceeded time-wait socket is immediately destroyed and warning is printed. 
官方文档没有说明默认值,通过几个系统的简单验证,初步确定默认值是180000。
官方手册中有一段警告:
    This limit exists only to prevent simple DoS attacks, you _must_ not lower the limit artificially, but rather increase it (probably, after increasing installed memory),if network conditions require more than default value.
基本意思是这个用于防止Dos攻击,我们不应该人工减少,如果网络条件需要的话,反而应该增加。

SO_LINGER详解:

SO_LINGER是一个socket选项,通过setsockopt API进行设置,使用起来比较简单,但其实现机制比较复杂

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完成。

参考文章:

1,https://blog.csdn.net/qzcsu/article/details/72861891
2,https://blog.csdn.net/knowledgebao/article/details/84644233
3,https://blog.csdn.net/yunhua_lee/article/details/8146837
4,http://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt


有任何问题,请联系:knowledgebao@163.com

TIME_WAIT状态的原因及解决办法相关推荐

  1. Socket高并发出现TIME_WAIT的原因以及解决办法

    最近公司项目遇到个问题,在Socket并发量较大的情况下,每次服务端发送完数据后,Sevice端采取主动Close的方断开连接.客户端用短连接的方式发送请求,会出现大量请求返回TIME_WAIT的现象 ...

  2. 网络 TCP的头部 3次握手和4次挥手 出现大量TIME_WAIT或CLOSE_WAIT的原因及解决办法

    TCP头部结构 16位源端口:标识发送方端口 16位目的端口:标识接受方端口 32位序列号:数据按照序列号传输,如果接收方接受后的数据序列号出现错误,可以根据此序号重新排列 32位确认号:接受方接受到 ...

  3. 服务器大量TIME_WAIT和CLOSE_WAIT的原因及解决办法

    原文:https://www.cnblogs.com/whx7762/p/9413787.html 今天登陆服务器想查看一个端口的占用情况,发现好多TIME_WAIT的情况,吓我一跳. 如下是TCP ...

  4. mysql sleep详解_mysql sleep链接过多的原因及解决办法

    今天收到运维同事短信,说有个线上业务"可能是数据库DB堵塞了,导致mysql链接过多,让我看一下". 回家后赶紧用家里vpn登录数据库服务器,show processlist 看了 ...

  5. IE6,IE7,FF等浏览器不兼容原因及解决办法(转)

    IE6,IE7,FF等浏览器不兼容原因及解决办法 2008-07-15 11:26 本文转载,作者:阿里巴巴前端开发,发到这里只是方便以后查看,也给各位需要的朋友. 浏览器的不兼容,大家肯定都是深恶痛 ...

  6. Session莫名丢失的原因及解决办法[转载]

    Asp.net 默认配置下,Session莫名丢失的原因及解决办法 正常操作情况下Session会无故丢失.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定成 ...

  7. 内存泄漏的原因及解决办法_探索内存碎片化 - 第288篇

    相关历史文章(阅读本文之前,您可能需要先看下之前的系列 ) 色谈Java序列化:女孩子慎入 - 第280篇 烦不烦,别再问我时间复杂度了:这次不色,女孩子进来吧 - 第281篇 双向链表,比西天还远? ...

  8. mysql数据库什么情况下会锁表_mysql数据库锁的产生原因及解决办法

    数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性 ...

  9. mysql数据库死锁的产生原因及解决办法

    该文章为转载,如有侵权请及时联系 这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据 ...

最新文章

  1. 最小生成树基础算法(Prim + Krustal)
  2. mybatis generator修改默认生成的sql模板
  3. websocket 发送图片_基于WebSocket的web端IM即时通讯应用的开发
  4. STM32之独立看门狗原理
  5. 618 技术特辑(二)几百万人同时下单的秒杀,为什么越来越容易抢到了?
  6. SCUT - 243 - 宝华复习 - 二分 - 桶计数
  7. 阿里MySQL读写一致_缓存与数据库读写一致的解决方案
  8. wpf中button的无边框实现
  9. 老手萌新学习composer的使用
  10. html中transition默认,CSS3中的Transition详解
  11. Cmdkey 凭证管理器工具
  12. 2019美赛B题PSO算法
  13. 2021国内地址数据库表mysql
  14. 修改scrollbars的样式
  15. 江浦街的汉庭酒店只有雨季
  16. AB计算机总线,什么是总线?简要说明AB、DB、CB的含义及其性能?
  17. java电子配件公司仓库管理系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  18. html弹出div弹窗
  19. 负边距在布局中的使用 BY:色拉油啊油
  20. 1067 - Invalid default value for ‘TIME_STAMP_‘的错误解决

热门文章

  1. 2008年《斯坦福大学开放课程: 编程方法学》(Open Stanford Course : Programming Methodology )[人人影视中英双语字幕][WMV]
  2. 【Scratch-外观模块】马赛克特效指令
  3. (附源码)基于PHP的酒店住宿管理系统 毕业设计261455
  4. [附源码]java毕业设计星期八酒店管理系统
  5. codeforces 978D 模拟思维
  6. MySQL查看当前使用的配置文件my.cnf的方法
  7. 剑网3手游微信第一个服务器,剑网3手游一开服就有大批网友涌入,不过服务器质量令人唏嘘...
  8. mvc4 renderpartial html,MVC4使用嵌套@ Html.RenderPartial()抛出编译器错误信息:CS1502...
  9. Android复习笔记(12) -handler的使用
  10. linux系统查看机器硬件信息,linux系统查看硬件信息的方法