前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP TIME_WAIT

TCP TIME_WAIT

原创
作者头像
用户1638080
修改2018-12-07 11:20:53
2.1K0
修改2018-12-07 11:20:53
举报
文章被收录于专栏:网络 后台网络 后台

TCP TIME_WAIT状态理解:

下面是tcp状态图(来自下面的参考文章):

从图中可以看出,若服务器主动关闭连接,在四次挥手的最后一个ACK后连接端口会变为TIME_WAIT状态, 状态停留时长为两个MSL(最大分段寿命),这个状态只有在主动关闭连接方会出现, 另一端可以在连接断开后立刻投入后续使用。

MSL是一个TCP分段可以存在于互联网系统中的最大时长,RFC 793指出MSL为2分钟, 但在LINUX系统中一般为30s,通过下面这个命令可以确定一些LINUX系统上的MSL数值:

sysctl net.ipv4.tcp_fin_timeout

当TCP连接处于TIME_WAIT这个状态时,标准中定义这个连接的插口(源Ip, 源端口,目的Ip,目的端口)不能再被使用,任何迟到的报文段都会被丢弃。 而大多数的TCP实现强加了更严格的限制, 在TIME_WAIT状态下,处于这个连接的本地端口默认情况下都不能再被使用,同时为了防止处于TIME_WAIT端口的主机出现故障,重启后马上建立新连接, RFC793有规定, TCP在重启动后的MSL秒内不能建立任何连接。

TIME_WAIT状态限制是比较严格的,设置TIME_WAIT状态主要有两个目的:

1、为了防止一个连接的延迟分段被后面新建的连接接收。连接是通过四元组(源Ip, 源端口,目的Ip,目的端口)来确定的, 虽然延迟包的序列号要满足新建连接的要求才能被接受,但是如果没有TIME_WAIT状态,新的连接还是有可以接收到上一个连接的延迟包,这个在RFC1337中有定义。

2、为了确保远程端已关闭连接。关闭端口的最后一个ACK有可能会丢失, 另一端可能会超时并重发最后的FIN, 保持TIME_WAIT状态可以让TCP再次发送最后的ACK。另外如果没有TIME_WAIT状态的话, 可以重新打开连接, 远程端可能会认为这个连接仍然是有效果的, 但它收到序列号匹配的SYN时, 它会回RST终止新连接并显示错误。

从上述两点原因来看, 有TIME_WAIT状态是比较保险的。


TCP TIME_WAIT可能出现问题以及参数调整:

当服务器上存在大量连接的时候,TIME_WAIT状态就会变得比较麻烦,连接表里有大量处于TIME_WAIT状态的连接,会导致新的连接不能够建立,同时它还会占用系统资源,这个就会限制服务器能处理的连接数目。

对于两个服务器之间处理数据, 它们的目标地址和目标端口可能是不变的, 在Linux上,默认情况下动态端口范围是49152~65535, 这也就意味着每分钟服务器之间能建立的连接是很有限的, 一旦被占用就不能投入使用了。

最好的解决办法还是增加更多的四元组组合(源IP,源端口, 目的IP,目的端口), 不过按照之前提到的,在更严格的限制下, 处于TIME_WAIT状态下的本地端口都不能再使用了。所以最好的不出错的解决方案是:

1、 通过修改net.ipv4.ip_local_port_range来增加客户端端口数目

2、 部署更多的客户端程序,能有更多的客户端IP。

有些时候可能会通过调整net.ipv4.tcp_tw_reusenet.ipv4.tcp_tw_recycle来尝试解决这个问题,但是这个都是有风险的,接下来会对这几个参数进行介绍。

和这方面相关的参数有以下几个:

l net.ipv4.tcp_fin_timeout

这个参数指定了在套接字强行关闭之前,等待最终FIN数据包的秒数, 对应的是主动关闭端FIN_WAIT-2的状态, 默认值是60s。通过修改这个值也可以缩短连接关闭时间,这个和TIME_WAIT的持续时间无关。FIN_WAIT-2套接字最多需要1.5k的内存,如果调长这个值,有可能的风险是大量套接字处于这个状态导致内存溢出,虽然单位占用内存少, 但是持续的时间长。

l net.ipv4.tcp_timestamps

这个参数可以被用于保障TCP传输的可靠性即用于PAWS机制,防范在高带宽下,TCP序列号在较短时间内就被重复使用,同一条TCP流在短时间内出现序号一样的两个合法数据包及其确认包。服务也可以通过包里带的时间戳,更加准确的计算RTT。

tcp_timestamp参数的默认取值为1, 表示收发包使用时间戳。 它的取值在Linux 4.10后的版本里做了些修改, 0表示关闭时间戳功能, 1 表示在收发包时不仅利用当前时间戳,还会利用每个连接生成的随机偏移量,2 表示只使用当前时间戳。

如果要使用后面两个参数,这个值需要置为非0。

*** 当tcp连接发起方处于NAT网络中, 向同一服务器发起请求时, 每个设备的时间戳不一定会递增, 有可能会导致有些连接一直被rst, 连接不上, 所以在NAT网络中的服务器开启timestamp有风险。

l net.ipv4.tcp_tw_reuse

为了提高高带宽下tcp的性能, RFC1323中定义了一个新的TCP选项, 包含了两个4字节时间戳字段, 第一个字段存储的是tcp发送选项时的当前时钟时间戳, 另一个字段存储的是从远端接收到的最新时间戳。

通过启用tcp_tw_reuse,如果新时间戳严格大于先前连接记录的时间戳, linux可以重复使用在TIME_WAIT状态的已有连接作为传出连接,发送数据, 这个传出连接在连接变为TIME_WAIT状态的1s之后就可以重用。

因为使用了时间戳, 重复的延迟包会带有过期的时间戳, 就会被丢弃, 因此避免了延迟包被新连接接收。此外也可以避免远程端丢失最后一个关闭连接的ACK,处于LASK-ACK状态而一直重发FIN,因为新建立的连接会发送一个SYN包, 它收到FIN包以后可以发送RST, 让远程端结束LASK-ACK状态。

这种方式对于传入连接没有什么帮助。

*** tcp_tw_reuse开启同样也有风险,正因为使用了时间戳,带着过期时间戳的包会被丢弃,因此同样会有上述所说问题, 在NAT网络中的客户端,有可能由于有些机器的时间戳远小于其他机器,导致tcp服务异常。

l net.ipv4.tcp_tw_recycle

启用这个选项,能够更快速的回收TIME_WAIT套接字,这种机制也依赖时间戳选项,它将会在超时重传(RTO)间隔后移除TIME_WAIT状态。

为了保证开启选项后, 也能达到TIME_WAIT状态同样的效果,它会记录远程端发来数据的最新时间戳,在TIME_WAIT状态生效期内,放弃所有时间戳小于记录时间戳的包。

*** 如果远端服务器处于NAT网络中, NAT网络中设备的机器时间戳可能不是统一的, 有可能会造成一些机器无法正常和远端通信,所有包都被丢弃,因此最好不要开启这个选项。

目前这个选项已经在Linux4.12以后的版本里被移除了。

参考文章:

https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TCP TIME_WAIT状态理解:
  • TCP TIME_WAIT可能出现问题以及参数调整:
    • l net.ipv4.tcp_fin_timeout
      • l net.ipv4.tcp_timestamps
        • l net.ipv4.tcp_tw_reuse
          • l net.ipv4.tcp_tw_recycle
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
          http://www.vxiaotou.com