首页 > 其他分享 >TCP TIME_WAIT状态优化

TCP TIME_WAIT状态优化

时间:2024-05-13 19:21:10浏览次数:24  
标签:状态 TCP 关闭 TIME 连接 WAIT

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

 

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

 

TIME_WAIT状态连接过多的危害

 

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

 

相关原理

 

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

 

什么是TIME_WAIT连接?

 

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

 

TCP三次握手

 

  1. 第一次握手:客户端发送一个SYN包给服务端,然后进入到SYN_ SENT状态
  2. 第二次握手:处在监听状态的服务端收到客户端的SYN包后进行回应:发送一个ACK包给客户端,同时发送一个SYN包给客户端, 然后进入到SYN_ RCVD状态
  3. 第三次握手:客户端在收到服务端的SYN包后发送一个ACK包进行确认, 然后进入到ESTABLISHED (连接成功状态)。服务端在收到ACK包后也进入ESTABLISHED (连接成功状态)

 

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

 

TCP四次挥手

 

  1. 第一次挥手:客户端先发送一个FIN包给服务端,然后进入到FIN _WAIT1 (终止等待1)状态
  2. 第二次挥手:服务端收到FIN包之后对其进行回应:发送一个ACK包给客户端, 然后进入到close__ wait (关闭等待)状态。这时候服务端处于半关闭状态。
  3. 第三次挥手:同时服务端也请求关闭连接,发送一个FIN包给客户端, 然后进入LAST__ ACK (最后确认)状态
  4. 第四次挥手:客户端在收到服务端发送的ACK包之后进入到FIN__ WAIT2 (终止等待2)状态,对服务端发来的FIN包进行回应:发送一个ACK包给服务端, 然后进入到TIME__WAIT (时间等待)状态,等待2MSL (最长报文段寿命)后进入关闭状态,服务端在收到客户端发来的ACK包之后立即进入关闭状态

 

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

 

为什么要有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]}'

 

如何优化

 

 

前面我们讲过,出现一定数量的TIME_WAIT连接是正常现象,但是在线上生产环境面对高并发场景时可能会出现极端的情况——大量的TIME_WAIT连接

 

大量的TIME_WAIT连接会占用系统本地端口,导致不能再创建新的TCP连接

 

那么我们要怎么进行优化呢?

 

大量的TIME_WAIT连接存在,其本质原因是什么?

 

1.大量的短连接存在

 

在HTTP/1.0协议中默认使用短连接。

 

也就是说,浏览器和服务器每进行一次HTTP操作,就会建立一次连接,任务结束后就会断开连接,而断开连接这个请求是由server去发起的,主动关闭连接请求一端才会有TIME_WAIT状态连接

 

2.HTTP请求头里connection值被设置为close

如果HTTP请求中,connection的值被设置成close,那就相当于告诉server:server执行完HTTP请求后去主动关闭连接

 

 

优化

 

客户端层面

 

我们可以在客户端将HTTP请求头里connection的值设置为:keep-alive。将短连接改成长连接

 

长连接比短连接从根本上减少了server去主动关闭连接的次数,减少了TIME_WAIT状态连接的产生

 

(在利用nginx做反向代理时,如果要设置成长连接,则需要设置成:1.从client到nginx的连接是长连接。2.从nginx到server的连接是长连接)

 

服务器层面

我们可以通过修改服务器的系统内核参数来进行优化

 

1.允许将TIME_WAIT状态的socket重新用于新的TCP连接

 

这样的好处就是如果出现大量TIME_WAIT状态的连接,也能够将这些连接占用的端口重新用于新的TCP连接

 

$ vim /etc/sysctl.confnet.ipv4.tcp_tw_reuse = 1 #默认为0,表示关闭

 

2.快速回收TIME_WAIT状态的socket

 

$ vim /etc/sysctl.confnet.ipv4.tcp_tw_recycle = 1#默认为0,表示关闭

 

3.将MSL值缩减

 

linux中MSL的值默认为60s,我们可以通过缩减MSL值来使得主动关闭连接一端由TIME_WAIT状态到关闭状态的时间减少

 

但是这样做会导致延迟报文无法清除以及主动关闭连接一端不能收到重传来的FIN请求,也会影响很多基于TCP的应用的连接复用和调优

 

所以在实际生产环境中,需要谨慎操作

 

​
#查看默认的MSL值
$cat /proc/sys/net/ipv4/tcp_fin_timeout
​
#修改
$echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
​
或者
​
$ vim /etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 30

标签:状态,TCP,关闭,TIME,连接,WAIT
From: https://www.cnblogs.com/walkersss/p/18189817

相关文章

  • 调试-网络-如何查看tcp socket recv buffer size
    客户端与服务器建立tcp连接后,在服务器上执行ss-imdst目标IP地址来检查skmemrb值:tcpESTAB00192.168.99.124:ssh192.168.99.......
  • setTimeout模拟interval
    functionrunTimer(list=[ { delay:2000, text:'第一步延迟2s' }, { delay:3000, text:'第二步延迟3s' }, { delay:1000, text:'第三步延迟1s' }, ],cb=(text)=>{ console.log('渲染回调&......
  • CSharp: SunTimeCalculator
     usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;namespaceWebAppPdfDemo{///<summary>//////</summary>publicclassSunTimeCalculator{#region辅助函数///<......
  • UcOs-III 源码阅读: os_time.c
    对实时时钟源文件os_time.c进行源码阅读与注释://功能:Tick级别延时、时间延时、恢复延时中的任务、获取/设置系统Tick值、实时时钟滴答函数//Tick级别延时API:OSTimeDly(ticks)//时间延时API:OSTimeDlyHMSM(p_hmsm)//恢复延时API:OSTimeDlyResume(task_id)//获取系统T......
  • python 基本日期和时间类型 datetime
    datetime说明datetime模块提供了处理日期和时间的类。它可以帮助你执行日期和时间的计算、转换以及格式化等操作。模块包含了日期(date)、时间(time)、日期时间(datetime)、时间间隔(timedelta)、时区(tzinfo)等类。datetime类:用于操作日期和时间的类,包括年、月、日、时、分、秒等信息......
  • c# datetime iso 8601 格式
    ......
  • numba-Ahead of time
    参考文档:https://numba.pydata.org/numba-doc/latest/user/pycc.htmlCompilingcodeaheadoftime(运行之前编译代码)虽然numnb主要是Just-In-Time(运行时)编译,但也提供了Ahead-Of-Tiem(提前编译)的工具。优点:AOT编译提供了一个不依赖numba的编译扩展模块,它可以运行在没......
  • SystemVerilog -- 3.5 Wait fork
    Waitforkwaitfork允许mainthread等待,直到所有forkedthreads都结束。这在mainthread必须生成多个threads并在等待所有threads完成之前执行某些功能的情况下非常有用。Example我们将使用上一篇文章中相同的示例,其中3个threads并行启动,mainthread等待其中一......
  • TCP的四次挥手过程
    TCP连接是双向传输的对等的模式(全双工模式),就是说双方都可以同时向对方发送或接收数据。而断开的时候,也是双方都可以主动断开,此时需要经过四次挥手的过程,流程如下图所示:主动方发送FIN包给被动方,主动方状态变成FIN_WAIT_1,等待被动方的确认。此时主动方不能再发送数据。被动方收......
  • 无线通信模块通过TCP/IP协议实现与PC端的数据传输
    在当今的信息时代,无线通信技术的发展日新月异,为我们的工作和生活带来了极大的便利。其中,无线通信模块通过TCP/IP协议向PC端传送数据已经成为了一种常见的通信方式。本文将详细介绍这一过程的主要步骤和涉及的关键技术,并以WIFI模块为例,探讨如何在QT平台下实现数据的无线传输。一、......