高并发场景下大量TCP链接处于time_wait状态原因及优化思路分析

这篇具有很好参考价值的文章主要介绍了高并发场景下大量TCP链接处于time_wait状态原因及优化思路分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


问题现象

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

一般来讲,在高并发的场景中,出现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链接

tcp大量timewait,tcp/ip,网络,服务器

TCP三次握手

  1. 第一次握手:客户端发送一个SYN包给服务端,然后进入到SYN_ SENT状态
  2. 第二次握手:处在监听状态的服务端收到客户端的SYN包后进行回应:发送一个ACK包给客户端,同时发送一个SYN包给客户端, 然后进入到SYN_ RCVD状态
    第三次握手:客户端在收到服务端的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连接存在,其本质原因是什么?

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的应用的连接复用和调优

所以在实际生产环境中,需要谨慎操作文章来源地址https://www.toymoban.com/news/detail-760250.html

#查看默认的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状态原因及优化思路分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TCP连接不释放,应用产生大量CLOSE_WAIT状态TCP

    23年元旦期间,大家都沉浸在一片祥和的过节气氛当中。 “滴滴滴”,这头同事的电话响起,具体说些什么我也没太在意,但见同事接完电话之后展现出了一副懊恼夹杂着些许不耐烦的表情。 我不解问道:“怎么了?” 同事:“刚刚运营反馈系统开始刷白屏了,所有的请求

    2024年02月05日
    浏览(25)
  • 深入协议栈了解TCP的三次握手、四次挥手、CLOSE-WAIT、TIME-WAIT。

            TCP网络编程的代码网上很多,这里就不再赘述,简单用一个图展示一下tcp网络编程的流程:                 这三个函数都是系统调用,我们可以分为请求连接方和被动连接两部分,我们知道请求连接方并非都是client,为了方便,本文用client代表主动连接方,s

    2024年02月09日
    浏览(26)
  • 【计算机网络】深入理解TCP协议二(连接管理机制、WAIT_TIME、滑动窗口、流量控制、拥塞控制)

    正常情况下,TCP需要经过三次握手建立连接+四次挥手断开链接,下面看一个图: 服务器的状态变化: [CLOSED - LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接; [LISTEN - SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认

    2024年02月07日
    浏览(41)
  • 说一下什么是tcp的2MSL,为什么客户端在 TIME-WAIT 状态必须等待 2MSL 的时间?

    1.1 MSL MSL:Maximum Segment Lifetime报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间 1.2为什么存在MSL TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段,并且TTL的限制是基于跳数 1.3MSL大小定义 RFC文档中规定为2分钟,但是实际实现过程中

    2024年02月06日
    浏览(34)
  • k8s 大量 pod 处于 ContainerStatusUnknown 状态

    如图所示,nexus 正常运行,但产生了大量的状态不明的 pod,原因也无从所知 解决办法,删除多余的 pod,一个一个删除,非常费劲 获取 namespace 中状态为 ContainerStatusUnknown 的 pod,并删除 获取所有非 Running 状态下的 pod,并删除

    2024年02月07日
    浏览(39)
  • springboot配置http连接超时时间主动断开避免产生大量close_wait

    与客户端联调接口,通信方式使用http连接,客户端设置了发起请求后10s就断开连接,然后果不其然,我在服务端这边收到了大量的close_wait状态,最终导致接口不可用。 close_wait产生的原因就是客户端断开了连接但是没有发FIN给到服务端,所以服务端不知道还一直在跟客户端通

    2024年02月16日
    浏览(40)
  • java 多线程处理大量并发数据

    Java中多线程是一种处理数据的常见方式,它可以同时执行多个线程以提高程序的性能和效率。下面是一个使用多线程处理数据的示例代码: 在上面的代码中,我们创建了一个数组 data 来存储待处理的数据。然后,我们创建了一个线程数组 threads ,用于存储要执行的线程。 通

    2024年02月09日
    浏览(42)
  • Java高并发系列: 使用wait - notify实现高效异步方法

    在项目开发中, 通常会有异步执行操作, 例如: 提交一个异步清空一系列数据库中ID = ${_id} 的记录, 这个时候通常的做法是主线程将任务添加到一个异步队列中, 后台维护一个线程不断地 循环 扫描这个队列, 如果有需要执行的任务, 则执行相应的逻辑. 如下图所示: 代码实现如下

    2024年02月09日
    浏览(40)
  • 【Kafka超时问题(已解决),kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection w】

    1.Kafka正常运行一段时间后,用测试工具发送数据时报了错: 2.于是单独用黑窗口启动Kafka,看看具体报啥错: 3.原因 JDK版本和Kafka版本不匹配 。 (我手里项目较多,用的JDK版本也不一样,有的时候忘了把JDK切换回去,就报了这个错)。 我的Kafka版本: 更换JDK版本或Kafka版本

    2024年02月09日
    浏览(37)
  • 【Java|多线程与高并发】wait和notify方法详解

    在Java多线程环境中,线程之间是抢占式执行的,线程的调度是随机的.这就很难受了. 在很多情况下我们希望线程以我们想要的顺序来执行. 这就需要 wait 和 notify 这两个方法 首先是 wait 方法 wait是 Object 类的方法,而Java中的类都是间接或直接继承于Object类. 因此只要是类的实例都可

    2024年02月10日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包