关于 time wait

关于 time waittodo:1,把文件整理一下2,看一下那些问题的处理文章3,仔细看一下这个文章:深入tcp网上有很多关于timewait的问题和修改方案,究竟什么是timewait?作用是什么?会造成什么问题?如何解决?我们接下来一点一点看一下。一,timewait是什么?timewait状态是TCP链接的主动关闭方会有的状态,在发出最后一个ACK包之后,主动关闭…

大家好,又见面了,我是你们的朋友全栈君。

网上有很多关于 time wait 的问题和修改方案,究竟什么是 time wait?作用是什么?会造成什么问题?如何解决?我们接下来一点一点看一下。

一,time wait 是什么?

timewait 状态是 TCP 链接的主动关闭方会有的状态,在发出最后一个 ACK 包之后,主动关闭方进入 timewait 状态,以确保 ACK 包到达对端,以及等待网络中之前迷路的数据包完全消失,防止在端口被复用的时候收到迷路包从而出现收包错误。
这里写图片描述

二,作用是什么?

上面在介绍 time wait 时已经说了,下面再详细说一下:

可靠地实现TCP全双工连接的终止

TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发出的,如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。
因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态 。

允许老的重复分节在网络中消逝

TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。为了避免这个情况,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。

三,会造成什么问题?

time wait 的主要作用是保证关闭的TCP端口不立即被使用,来避免上面说的可能会发生的问题。也就是说,time wait 过多的话,可能造成端口无法使用。

TIME_Wait的主要作用是保证关闭的TCP端口不立即被使用。因为当网络存在延迟时,可能当某个端口被关闭后,网络中还有一些重传的TCP片在发向这个端口,如果这个端口立即建立新的TCP连接,则可能会有影响。所以使用2倍的MSL时间来限制这个端口立即被使用。这个等待时间基本是从1981年的RFC793过来的,对于服务器实在太长了些。而且每个TCP连接都各自有个数据结构,叫TCP Control block,Time_wait的时候这个数据结构没有被释放。所以当有太多的TCP连接时,内存可能会被占用很多。

如果有恶意程序大量的连接服务器,虽然很快断开,但产生大量的TIME_WAIT,逐渐消耗内存。虽然可以通过setsockopt(nListenSocket, SOL_SOCKET, SO_REUSEADDR, &nRet, n);让TIME_WAIT的本地地址和端口被新的进程使用,但系统给新进程分配的端口貌似只有一小部分落到了TIME_WAIT端口,还是无法解决TIME_WAIT带来的问题。

目前好像只能在TIME_WAIT的时间限制上做点文章了,不少管理员同志设置成30秒,至少能缓解服务器在高连接情况下的很大压力

四,如何解决 time wait 过多问题

1,使用长连接
使用长连接的话,会减少连接创建, 也就会减少 time wait 的产生。关于长连接,请参看:关于 Nginx 和 Tomcat 的 http 长连接设置

2,设置 tcp_tw_reuse
tcp_tw_reuse:顾名思义就是复用TIME_WAIT连接。当创建新连接的时候,如果可能的话会考虑复用相应的TIME_WAIT连接。通常认为「tcp_tw_reuse」比「tcp_tw_recycle」安全一些,这是因为一来TIME_WAIT创建时间必须超过一秒才可能会被复用;二来只有连接的时间戳是递增的时候才会被复用。官方文档里是这样说的:如果从协议视角看它是安全的,那么就可以使用。这简直就是外交辞令啊!按我的看法,如果网络比较稳定,比如都是内网连接,那么就可以尝试使用。

不过需要注意的是在哪里使用,既然我们要复用连接,那么当然应该在连接的发起方使用,而不能在被连接方使用。举例来说:客户端向服务端发起HTTP请求,服务端响应后主动关闭连接,于是TIME_WAIT便留在了服务端,此类情况使用「tcp_tw_reuse」是无效的,因为服务端是被连接方,所以不存在复用连接一说。让我们延伸一点来看,比如说服务端是PHP,它查询另一个MySQL服务端,然后主动断开连接,于是TIME_WAIT就落在了PHP一侧,此类情况下使用「tcp_tw_reuse」是有效的,因为此时PHP相对于MySQL而言是客户端,它是连接的发起方,所以可以复用连接。

说明:如果使用tcp_tw_reuse,请激活tcp_timestamps,否则无效。

3,设置 tcp_max_tw_buckets
顾名思义就是控制TIME_WAIT总数。官网文档说这个选项只是为了阻止一些简单的DoS攻击,平常不要人为的降低它。如果缩小了它,那么系统会将多余的TIME_WAIT删除掉,日志里会显示:「TCP: time wait bucket table overflow」。

需要提醒大家的是物极必反,曾经看到有人把「tcp_max_tw_buckets」设置成0,也就是说完全抛弃TIME_WAIT,这就有些冒险了,用一句围棋谚语来说:入界宜缓。

4,不要设置 tcp_tw_recycle
顾名思义就是回收TIME_WAIT连接。可以说这个内核参数已经变成了大众处理TIME_WAIT的万金油,如果你在网络上搜索TIME_WAIT的解决方案,十有八九会推荐设置它,不过这里隐藏着一个不易察觉的陷阱

当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。参考:tcp_tw_recycle和tcp_timestamps导致connect失败问题

有的地方说设置 tcp_fin_timeout。这个是在 fin_wait_2 状态的停留的时间,这个时间越短,到 time wait 状态的时间就越快。但这个是在连接关闭接收方半天不返回 Fin 的基础上的。如果很快就返回 Fin 那么这个值没什么作用。

还有的地方意思是修改 tcp_fin_timeout,就是修改 time wait 的 MSL 时间,但其实不是这样的。MSL指的是报文段的最大生存时间,如果报文段在网络活动了MSL时间,还没有被接收,那么会被丢弃。关于MSL的大小,RFC 793协议中给出的建议是两分钟,不过实际上不同的操作系统可能有不同的设置,以Linux为例,通常是半分钟,两倍的MSL就是一分钟,也就是60秒,并且这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它:

define TCP_TIMEWAIT_LEN (60*HZ)

五,总结

1,从客户端和服务器端总结

对于客户端
1. 作为客户端因为有端口65535问题,TIME_OUT过多直接影响处理能力,打开tw_reuse 即可解决,不建议同时打开tw_recycle,帮助不大。
2. tw_reuse 帮助客户端1s完成连接回收,基本可实现单机6w/s请求,需要再高就增加IP数量吧。
3. 如果内网压测场景,且客户端不需要接收连接,同时tw_recycle 会有一点点好处。
4. 业务上也可以设计由服务端主动关闭连接

对于服务端
1. 打开tw_reuse无效
2. 线上环境 tw_recycle 不要打开
服务器处于NAT 负载后,或者客户端处于NAT后(这是一定的事情,基本公司家庭网络都走NAT);公网服务打开就可能造成部分连接失败,内网的话到时可以视情况打开;像我所在公司对外服务都放在负载后面,负载会把timestamp 都给清空,好吧,就算你打开也不起作用。

  1. 服务器TIME_WAIT 高怎么办
    不像客户端有端口限制,处理大量TIME_WAIT Linux已经优化很好了,每个处于TIME_WAIT 状态下连接内存消耗很少,而且也能通过tcp_max_tw_buckets = 262144 配置最大上限,现代机器一般也不缺这点内存。

2,名词总结

  1. MSL 由来
    发起连接关闭方回复最后一个fin 的ack,为避免对方ack 收不到、重发的或还在中间路由上的fin 把新连接给干掉了,等个2MSL,4min。也就是连接有谁关闭的那一方有time_wait问题,被关那方无此问题。

  2. reuse、recycle
    通过timestamp的递增性来区分是否新连接,新连接的timestamp更大,那么小的timestamp的fin 就不会fin掉新连接。

  3. reuse
    通过timestamp 递增性,客户端、服务器能够处理outofbind fin包

  4. recycle
    对于服务端,同一个src ip,可能会是NAT后很多机器,这些机器timestamp递增性无可保证,服务器会拒绝非递增请求连接。

3,查看 time wait 的命令

  • ss -s
  • netstat -n | awk ’/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

参考:

关于 time wait:

TIME_WAIT状态详解:关于 time wait 的存在的作用,也是它要解决的问题。
TIME_WAIT状态在tcp连接中的含义与作用:也是关于 time wait 的存在的作用。这个讲的更多,挺仔细的,虽然有的地方讲的重复了。
理解TIME_WAIT:讲的非常好,讲了 time wait 原理,还有一些 time wait 多过的解决方法。
再叙TIME_WAIT:解决 time wait 方法总结的非常好,还有一些案例。
tcp_tw_reuse、tcp_tw_recycle 使用场景及注意事项:非常好的总结,从客户端和服务器端进行了总结。

关于 4 次挥手:

TCP协议中的三次握手和四次挥手(图解):里面关于 4 次挥手的解释非常好。
TCP的三次握手、四次挥手–非常详细讲解:里面讲的状态迁移非常好。还讲解了每次挥手是关闭读还是写。
TCP/IP状态图的TIME_WAIT作用:4 次挥手的文字流程讲的很好

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/132692.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 更新pycharm版本_pycharm怎么更改python环境

    更新pycharm版本_pycharm怎么更改python环境如下图,记录要勾选Makeavaliabletoallprojects,然后查看是否加载出所有的第三方插件,会遇到插件安装后,运行还是找不到插件的问题,就是这里选择的不对,Pycharm总是会自己修改Baseinterperter路径,安装好后,在这里修改路径,看到有加载出来就可以了…

  • UVa 10054 : The Necklace 【欧拉回路】

    UVa 10054 : The Necklace 【欧拉回路】

  • SpringBoot自动装配原理(简单易懂)

    SpringBoot自动装配原理(简单易懂)1、什么是自动装配自动装配就是把别人(官方)写好的config配置类加载到spring容器,然后根据这个配置类生成一些项目需要的bean对象。(小声逼逼:就像我们自己在项目了写的config配置类一样的,只不过这个是别人写好的,你什么都不用管)2、自动装配的开关在哪里@SpringBootApplication|–@EnableAutoConfiguration|–@Import({AutoConfigurationImportSelector.class})在@Spri

  • 友盟多渠道获取渠道名,后台显示市场标识

    友盟多渠道获取渠道名,后台显示市场标识

  • Java开源博客源码完整汇总(持续更新)

    Java开源博客源码完整汇总(持续更新)程序员需要拥有一个属于自己的独立博客网站。所以我从网站收集了一些好的Java开源博客系统。既然是属于开源,当然支持我们广大程序员二次开发了。其实搭建属于自己的技术博客网站很简单,只需要一个域名,一台服务器,然后进行网站备案(个人备案很简单)就可以拥有属于自己的博客网站了。程序员一定要及早的打造个人独立IP,拥有自己的独立博客,学会扩大自己的影响力。在公司,你能力最多影响公司的同事。但是在互联网,拥有自己的网站,你就可以影响千千万万的程序员和即将入行的新手程序员1.OneBlog一个简洁美观、功能.

  • SQL中的DECIMAL()函数

    SQL中的DECIMAL()函数    Decimal为SQL Server数据类型,属于浮点数类型。一个decimal类型的数据占用了2~17个字节。    Decimal 数据类型Decimal变量存储为96位(12个字节)无符号的整型形式,    D

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号