共计 3773 个字符,预计需要花费 10 分钟才能阅读完成。
起源:http://ningg.top/computer-bas…
几个方面:
- 问题形容:什么景象?什么影响?
- 问题剖析
- 解决方案
- 底层原理
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. 附录
几个方面:
- TCP 连贯状态的查问
- MSL 工夫
- 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,“报文最大生存工夫”,
- 任何报文在网络上存在的最长工夫,超过这个工夫报文将被抛弃。(IP 报文)
- TCP 报文(segment)是 ip 数据报(datagram)的数据局部。
Tips:
RFC 793 中规定 MSL 为 2 分钟,理论利用中罕用的是 30 秒,1 分钟和 2 分钟等。
2MSL,TCP 的 TIME_WAIT
状态,也称为2MSL 期待状态:
- 当 TCP 的一端发动被动敞开(收到 FIN 申请),在收回最初一个 ACK 响应后,即第 3 次握 手实现后,发送了第四次握手的 ACK 包后,就进入了 TIME_WAIT 状态。
- 必须在此状态上停留两倍的 MSL 工夫,期待 2MSL 工夫次要目标是怕最初一个 ACK 包对方没收到,那么对方在超时后将重发第三次握手的 FIN 包,被动敞开端接到重发的 FIN 包后,能够再发一个 ACK 应答包。
- 在 TIME_WAIT 状态时,两端的端口不能应用,要等到 2MSL 工夫完结,才可持续应用。(IP 层)
- 当连贯处于 2MSL 期待阶段时,任何早退的报文段都将被抛弃。
不过在理论利用中,能够通过设置「SO_REUSEADDR 选项」,达到不用期待 2MSL 工夫完结,即可应用被占用的端口。
附录 C:TCP 三次握手和四次握手
具体细节,参考:
- TCP 的三次握手与四次挥手(详解 + 动图)
具体示意图:
- 三次握手 ,
建设
连贯过程 - 四次挥手 ,
开释
连贯过程
几个外围疑难:
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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!