关于java:面试官大量-TIMEWAIT-状态-TCP-连接对业务有什么影响怎么处理

25次阅读

共计 3773 个字符,预计需要花费 10 分钟才能阅读完成。

起源:http://ningg.top/computer-bas…

几个方面:

  1. 问题形容:什么景象?什么影响?
  2. 问题剖析
  3. 解决方案
  4. 底层原理

1. 问题形容

模仿高并发的场景,会呈现批量的 TIME_WAIT 的 TCP 连贯:

短时间后,所有的 TIME_WAIT 全都隐没,被回收,端口包含服务,均失常。

即,在高并发的场景下,TIME_WAIT 连贯存在,属于失常景象。

线上场景中,继续的高并发场景

  • 一部分 TIME_WAIT 连贯被回收,但新的 TIME_WAIT 连贯产生;
  • 一些极其状况下,会呈现 大量 TIME_WAIT 连贯。

Think:

上述大量的 TIME_WAIT 状态 TCP 连贯,有什么业务上的影响吗?

Nginx 作为反向代理时,大量的短链接,可能导致 Nginx 上的 TCP 连贯处于 time_wait 状态:

  • 每一个 time_wait 状态,都会占用一个「本地端口」,下限为 65535(16 bit,2 Byte);
  • 当大量的连贯处于 time_wait 时,新建设 TCP 连贯会出错,address already in use : connect 异样

统计 TCP 连贯的状态:

// 统计:各种连贯的数量
$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 1154
TIME_WAIT 1645

Tips:

TCP 本地端口数量,下限为 65535(6.5w),这是因为 TCP 头部应用 16 bit,存储「端口号」,因而束缚下限为 65535

2. 问题剖析

大量的 TIME_WAIT 状态 TCP 连贯存在,其本质起因是什么?

  • 大量的 短连贯 存在
  • 特地是 HTTP 申请中,如果 connection 头部取值被设置为 close 时,根本都由「服务端 」发动 被动敞开连贯
  • 而,TCP 四次挥手 敞开连贯机制中,为了保障 ACK 重发 抛弃提早数据,设置 time_wait 为 2 倍的 MSL(报文最大存活工夫)

TIME_WAIT 状态:

  • TCP 连贯中,被动敞开连贯 的一方呈现的状态;(收到 FIN 命令,进入 TIME_WAIT 状态,并返回 ACK 命令)
  • 放弃 2 个 MSL 工夫,即,4 分钟;(MSL 为 2 分钟)

3. 解决办法

解决上述 time_wait 状态大量存在,导致新连贯创立失败的问题,个别解决办法:

1、客户端 ,HTTP 申请的头部,connection 设置为 keep-alive,放弃存活一段时间:当初的浏览器,个别都这么进行了 2、 服务器端

  • 容许 time_wait 状态的 socket 被 重用
  • 缩减 time_wait 工夫,设置为 1 MSL(即,2 mins)

更多细节,参考:

https://www.cnblogs.com/yjf51…

论断:几个外围要点

1、time_wait 状态的影响

  • TCP 连贯中,「被动发动敞开连贯」的一端,会进入 time_wait 状态
  • time_wait 状态,默认会继续 2 MSL(报文的最大生存工夫),个别是 2×2 mins
  • time_wait 状态下,TCP 连贯占用的端口,无奈被再次应用
  • TCP 端口数量,下限是 6.5w(65535,16 bit)
  • 大量 time_wait 状态存在,会导致新建 TCP 连贯会出错,address already in use : connect 异样

2、事实场景

  • 服务器端,个别设置:不容许「被动敞开连贯」
  • 但 HTTP 申请中,http 头部 connection 参数,可能设置为 close,则,服务端解决完申请会被动敞开 TCP 连贯
  • 当初浏览器中,HTTP 申请 connection 参数,个别都设置为 keep-alive
  • Nginx 反向代理场景中,可能呈现大量短链接,服务器端,可能存在

3、解决办法:服务器端

  • 容许 time_wait 状态的 socket 被重用
  • 缩减 time_wait 工夫,设置为 1 MSL(即,2 mins)

4. 附录

几个方面:

  1. TCP 连贯状态的查问
  2. MSL 工夫
  3. TCP 三次握手和四次握手

附录 A:查问 TCP 连贯状态

Mac 下,查问 TCP 连贯状态的具体命令:

// Mac 下,查问 TCP 连贯状态
$ netstat -nat |grep TIME_WAIT

// Mac 下,查问 TCP 连贯状态,其中 -E 示意 grep 或的匹配逻辑
$ netstat -nat | grep -E "TIME_WAIT|Local Address"
Proto  Recv-Q Send-Q Local  Address  Foreign  Address  (state)
tcp4 0  0  127.0.0.1.1080  127.0.0.1.59061 TIME_WAIT

// 统计:各种连贯的数量
`$ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
`ESTABLISHED 1154
`TIME_WAIT 1645

附录 B:MSL 工夫

MSL,Maximum Segment Lifetime,“报文最大生存工夫”,

  1. 任何报文在网络上存在的最长工夫,超过这个工夫报文将被抛弃。(IP 报文)
  2. TCP 报文(segment)是 ip 数据报(datagram)的数据局部。

Tips:

RFC 793 中规定 MSL 为 2 分钟,理论利用中罕用的是 30 秒,1 分钟和 2 分钟等。

2MSL,TCP 的 TIME_WAIT 状态,也称为2MSL 期待状态

  1. 当 TCP 的一端发动被动敞开(收到 FIN 申请),在收回最初一个 ACK 响应后,即第 3 次握 手实现后,发送了第四次握手的 ACK 包后,就进入了 TIME_WAIT 状态。
  2. 必须在此状态上停留两倍的 MSL 工夫,期待 2MSL 工夫次要目标是怕最初一个 ACK 包对方没收到,那么对方在超时后将重发第三次握手的 FIN 包,被动敞开端接到重发的 FIN 包后,能够再发一个 ACK 应答包。
  3. 在 TIME_WAIT 状态时,两端的端口不能应用,要等到 2MSL 工夫完结,才可持续应用。(IP 层)
  4. 当连贯处于 2MSL 期待阶段时,任何早退的报文段都将被抛弃。

不过在理论利用中,能够通过设置「SO_REUSEADDR 选项」,达到不用期待 2MSL 工夫完结,即可应用被占用的端口。

附录 C:TCP 三次握手和四次握手

具体细节,参考:

  • TCP 的三次握手与四次挥手(详解 + 动图)

具体示意图:

  1. 三次握手 建设 连贯过程
  2. 四次挥手 开释 连贯过程

几个外围疑难:

1、time_wait 是「服务器端」的状态?or「客户端」的状态?

  • RE:time_wait 是「被动敞开 TCP 连贯」一方的状态,可能是「客服端」的,也可能是「服务器端」的
  • 个别状况下,都是「客户端」所处的状态;「服务器端」个别设置「不被动敞开连贯」

2、服务器在对外服务时,是「客户端」发动的断开连接?还是「服务器」发动的断开连接?

  • 失常状况下,都是「客户端」发动的断开连接
  • 「服务器」个别设置为「不被动敞开连贯」,服务器通常执行「被动敞开」
  • 但 HTTP 申请中,http 头部 connection 参数,可能设置为 close,则,服务端解决完申请会被动敞开 TCP 连贯

对于 Apache httpd 服务器的关联配置,参考:

https://elf8848.iteye.com/blo…

对于 HTTP 申请中,设置的被动敞开 TCP 连贯的机制:TIME_WAIT 的是被动断开刚才会呈现的,所以被动断开方是服务端?

  • 答案是是的。在 HTTP1.1 协定中,有个 Connection 头,Connection 有两个值,close 和 keep-alive,这个头就相当于客户端通知服务端,服务端你执行实现申请之后,是敞开连贯还是放弃连贯,放弃连贯就意味着在放弃连贯期间,只能由客户端被动断开连接。还有一个 keep-alive 的头,设置的值就代表了服务端放弃连贯放弃多久。
  • HTTP 默认的 Connection 值为 close,那么就意味着敞开申请的一方简直都会是由服务端这边发动的。那么这个服务端产生 TIME_WAIT 过多的状况就很失常了。
  • 尽管 HTTP 默认 Connection 值为 close,然而,当初的浏览器发送申请的时候个别都会设置 Connection 为 keep-alive 了。所以,也有人说,当初没有必要通过调整参数来使 TIME_WAIT 升高了。

对于 time_wait

1、TCP 连贯建设后,「被动敞开连贯」的一端,收到对方的 FIN 申请后,发送 ACK 响应,会处于 time_wait 状态;

2、time_wait 状态 ,存在的 必要性

  • 牢靠的实现 TCP 全双工连贯的终止:四次挥手敞开 TCP 连贯过程中,最初的 ACK 是由「被动敞开连贯」的一端收回的,如果这个 ACK 失落,则,对方会重发 FIN 申请,因而,在「被动敞开连贯」的一段,须要保护一个 time_wait 状态,解决对方重发的 FIN 申请;
  • 解决提早达到的报文:因为路由器可能抖动,TCP 报文会提早达到,为了防止「提早达到的 TCP 报文」被误认为是「新 TCP 连贯」的数据,则,须要在容许新创建 TCP 连贯之前,放弃一个不可用的状态,期待所有提早报文的隐没,个别设置为 2 倍的 MSL(报文的最大生存工夫),解决「提早达到的 TCP 报文」问题;

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 别在再满屏的 if/ else 了,试试策略模式,真香!!

3. 卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0