18年专业服务器托管租用服务商!
咨询热线 : 400-880-5868
帮助中心

如何优化服务器产生大量 TIME_WAIT

发布时间:2022-6-24 13:41:13    返回首页

  今天我们来探讨一下服务器产生大量 TIME_WAIT 状态的 TCP连接的情况。

  问题现象

  对一台服务器进行压测(模拟高并发场景),会发现大量 TIME_WAIT 状态的 TCP连接,连接关闭后,这些TIME_WAIT会被系统回收。

  v2-e0b3bd932fa65910e135cd0c3a8c74d8_720w

  一般来讲,在高并发的场景中,出现TIME_WAIT连接是正常现象,一旦四次握手连接关闭之后,这些连接也就随之被系统回收了。

  但是在实际高并发场景中,很有可能会出现这样的极端情况——大量的TIME_WAIT连接。

  TIME_WAIT状态连接过多的危害

  (1)TIME_WAIT 状态下,TCP连接占用的本地端口将一直无法释放。

  (2)如果TIME_WAIT连接把所有可用端口都占完了(TCP端口数量上限是65535)而且还未被系统回收,就会出现无法向服务端创建新的socket连接的情况,此时系统几乎停转,任何链接都不能建立:address already in use : connect 异常。

  相关原理

  在遇到一个问题时,我们不但要看到其现象,更要看到问题产生背后的原理是什么,这样不但解决了问题,还能够拓展自己的知识面。

  什么是TIME_WAIT连接?

  一般来讲,客户端(client)与服务端(server)之间的某个进程要进行通信时,在运输层层面来讲先要通过三次握手来建立TCP连接。

  TCP三次握手

  第一次握手:客户端发送一个SYN包给服务端,然后进入到SYN_ SENT状态。

  第二次握手:处在监听状态的服务端收到客户端的SYN包后进行回应:发送一个ACK包给客户端,同时发送一个SYN包给客户端, 然后进入到SYN_ RCVD状态。

  第三次握手:客户端在收到服务端的SYN包后发送一个ACK包进行确认, 然后进入到ESTABLISHED (连接成功状态)。服务端在收到ACK包后也进入ESTABLISHED (连接成功状态)。

  通信结束后,需要关闭连接,这时候就要通过TCP的四次挥手来进行关闭连接了。

  TCP四次挥手

  第一次挥手:客户端先发送一个FIN包给服务端,然后进入到FIN _WAIT1 (终止等待1)状态。

  第二次挥手:服务端收到FIN包之后对其进行回应:发送一个ACK包给客户端, 然后进入到close__ wait (关闭等待)状态。这时候服务端处于半关闭状态。

  第三次挥手:同时服务端也请求关闭连接,发送一个FIN包给客户端, 然后进入LAST__ ACK (最后确认)状态。

  第四次挥手:客户端在收到服务端发送的ACK包之后进入到FIN__ WAIT2 (终止等待2)状态,对服务端发来的FIN包进行回应:发送一个ACK包给服务端, 然后进入到TIME__WAIT (时间等待)状态,等待2MSL (最长报文段寿命)后进入关闭状态,服务端在收到客户端发来的ACK包之后立即进入关闭状态。

  从TCP四次挥手的过程我们可以看到,主动关闭连接的一端(注意这里是说主动关闭连接的一端,即 client 和 server 都可以是主动关闭连接的一端)在收到对方的FIN包请求之后,发送ACK包进行响应,这时候会处在TIME_WAIT状态。

  v2-f11f4b8069c6b917c14ea6edf94cb14e_r

  为什么要有TIME_WAIT状态?

  有很多同学可能不理解为什么会有TIME_WAIT这个状态,而且在这个状态下还要先等待2MSL(报文最大生存时间)后才真正关闭连接。

  首先,TIME_WAIT状态使得TCP全双工连接的终止更加可靠。

  我们知道,网络的本质是不可靠的,四次挥手关闭TCP连接的过程中,最后一个ACK包是由主动关闭连接一端发出的(这里我们假设是 client 进行主动关闭连接)。

  而这个ACK有可能在路上丢失,使得处在LAST_ACK状态的一端(server端)接收不到,如果接收不到,server 就会超时重传 FIN 请求。

  所以 client 需要处在TIME_WAIT状态并等待2MSL时间来处理 server 重传的 FIN 请求,来使得 server 能够正常关闭。

  其次,TIME_WAIT状态的存在可以处理延迟到达的报文

  网络的本质是不可靠的,也就意味着TCP报文有可能会延迟到达,TIME_WAIT状态时,两端的端口不能使用,要等到2MSL时间结束后才可以继续使用,并且在等待2MSL时间的过程中,任何迟到的报文都将被丢弃。

  这样就可以避免延迟到达的TCP报文被误认为是新TCP连接的数据,并且使得这些延迟报文在网络上消失。

  如何查看TIME_WAIT连接?

  以我本地虚拟机(CentOS7)为例:

  查看状态为TIME_WAIT的TCP连接。

  $ netstat -tan |grep TIME_WAIT

  统计TCP各种状态的连接数。

  $ netstat -n | awk /^tcp/ {++S[$NF]} END {for(i in S) print i, S[i]}

在线咨询
QQ 咨询
服务热线
扫一扫

扫一扫
关注我们

全国免费服务热线
400-880-5868

返回顶部