关于 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)


相关推荐

  • Idea主题风格插件Material Theme

    Idea主题风格插件Material Theme目录1idea插件material-theme设置2下载主题风格jar直接使用设置1idea插件material-theme偶然发现一款“暗黑系列”idea主题插件,感觉非常不错,分享一下~github:https://github.com/equinusocio/material-themeplugins安装完重启idea设置切换主题Edi…

  • jenkins 邮件_测试报告的基本内容

    jenkins 邮件_测试报告的基本内容前言前面已经实现在jenkins上展示html的测试报告,接下来只差最后一步,把报告发给你的领导,展示你的劳动成果了。安装EmailExtensionPlugin插件jenkins首页-

  • c#实现图片gif去水印「建议收藏」

    做项目时候会遇到在网络上爬的源文件,png图片或者动画gif背景都带有水印,“百度出品”“不得转载”等等,这样出来的文件放在项目里面当做自己的资源来用肯定是不可以的,现在就来用lockbits替换背景的颜色,实现水印消除的目的。话不多述,上图:处理前:这是处理之前的图,其实底部的“baidu汉语“看着并不是很明显(仔细看),仍然需要把字体的背部水印去掉,这里开始用lockbits来去水印了。处理

  • Jquery确认对话框弹出

    Jquery确认对话框弹出Jquery确认对话框弹出

  • C语言——五子棋人机对战

    C语言——五子棋人机对战         先说下背景吧,写下这篇博客时,博主大一在读,C语言初学者,寒假无事,便计划写几个由C语言实现的小游戏以提升编程能力。在这篇博客里分享的是可人机对战的五子棋游戏。         棋类游戏要实现初级的机器智能,其核心思想便是:感知(SENSE)->思考(THINK)->行动(ACT)。所以,本文将尽量以这个顺序介绍实现过程。(1)前期准备:    此程序中,机器…

  • 在Eclipse中使用JUnit5进行单元测试

    在Eclipse中使用JUnit5进行单元测试关于Junit的介绍:官方介绍:JUnit5是下一代的JUnit。其目标是为JVM上的开发端测试创建一个最新的基础。这包括关注Java8和以上,以及支持多种不同的测试风格。JUnit5是JUnitLambda及其在Indiegogo上众筹活动的结果。引用度娘的介绍如下:JUnit是一个Java语言的单元测试框架。它由KentBeck和ErichGamma建立,逐渐成…

发表回复

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

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