TIME_WAIT的危害

2024-06-20 05:12
文章标签 time wait 危害

本文主要是介绍TIME_WAIT的危害,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

该文章主要讨论下TIME_WAIT的存在意义和潜在危害,以及解决措施。

具体内容

首先看一下下面这幅图

这幅图来自《TCP IP详解卷1:协议 原书第2版中文》TCP状态变迁图。

TIME_WAIT存在意义
  • 可靠的终止TCP连接。
  • 保证让迟来的TCP报文有足够的时间被识别并丢弃。

假如用于确认服务器结束报文段6的TCP报文段7丢失,那么服务器要重发此结束报文段,客户端要在某个状态等待结束报文段然后回复确认报文段,这样才能可靠的终止TCP连接。

在linux系统上,一个TCP端口不能被同时打开多次,当一个TCP连接处于TIME_WAIT状态时,我们无法使用该链接的端口来建立一个新连接。反过来思考,如果不存在TIME_WAIT状态,则应用程序能过立即建立一个和刚关闭的连接相似的连接(这里的相似,是指他们具有相同的IP地址和端口号)。这个新的、和原来相似的连接被称为原来连接的化身。新的化身可能受到属于原来连接携带应用程序数据的TCP报文段(迟到的报文段),这显然是不该发生的。这是TIME_WAIT状态存在的第二个原因。

那么为什么TIME_WAIT的时间是2MSL呢?

  MSL是TCP报文的最大生命周期,因为TIME_WAIT持续在2MSL就可以保证在两个传输方向上的尚未接收到或者迟到的报文段已经消失,否则服务器立即重启,可能会收到来自上一个进程迟到的数据,但是这种数据很可能是错误的,同时也是在理论上保证最后一个报文可靠到达,假设最后一个ACK丢失,那么服务器会再重发一个FIN,这是虽然客户端的进程不在了,但是TCP连接还在,仍然可以重发LAST_ACK。

危害

问题来了,如果在QPS每秒几万以上的高并发的场景下,就会出现系统存在几万多个time_wait状态。虽然TIME_WAIT存在是解决之前说过的两个主要问题,但是TIME_WAIT状态过多会存在以下的问题:

(1)在socket的TIME_WAIT状态结束之前,该socket所占用的本地端口号将一直无法释放。

(2)在高并发(每秒几万qps)并且采用短连接方式进行交互的系统中运行一段时间后,系统中就会存在大量的time_wait状态,如果time_wait状态把系统所有可用端口 都占完了且尚未被系统回收时,就会出现无法向服务端创建新的socket连接的情况。此时系统几乎停转,任何链接都不能建立。

(3)大量的time_wait状态也会系统一定的fd,内存和cpu资源,当然这个量一般比较小,并不是主要危害

解决措施

  • 修改系统配置参数

修改/etc/sysctl.conf文件,一般为如下几个参数:

比较常用的更安全的设置是net.ipv4.tcp_tw_reuse

net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout =  修改系统默认的 TIMEOUT 时间
net.ipv4.tcp_max_tw_buckets = 5000 表示系统同时保持TIME_WAIT套接字的最大数量,(默认是18000). 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。一般不建议调整
net.ipv4.tcp_timestamps = 1(默认即为1)60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。也就是说服务器打开了 tcp_tw_reccycle了,就会检查时间戳,如果对方发来的包的时间戳是乱跳的或者说时间戳是滞后的,那么服务器就会丢掉不回包,现在很多公司都用LVS做负载均衡,通常是前面一台LVS,后面多台后端服务器,这其实就是NAT,当请求到达LVS后,它修改地址数据后便转发给后端服务器,但不会修改时间戳数据,对于后端服务器来说,请求的源地址就是LVS的地址,加上端口会复用,所以从后端服务器的角度看,原本不同客户端的请求经过LVS的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象,所以根据情况使用其他优化:net.ipv4.ip_local_port_range = 1024 65535 增加可用端口范围,让系统拥有的更多的端口来建立链接,这里有个问题需要注意,对于这个设置系统就会从1025~65535这个范围内随机分配端口来用于连接,如果我们服务的使用端口比如8080刚好在这个范围之内,在升级服务期间,可能会出现8080端口被其他随机分配的链接给占用掉,这个原因也是文章开头提到的端口被占用的另一个原因
net.ipv4.ip_local_reserved_ports = 7005,8001-8100 针对上面的问题,我们可以设置这个参数来告诉系统给我们预留哪些端口,不可以用于自动分配。

Linux 系统对于net.ipv4.tcp_tw_reuse的解释如下:

Allow to reuse TIME-WAIT sockets for new connections when it is safe from protocol viewpoint. Default value is 0.It should not be changed without advice/request of technical experts.

这段话的大意是从协议角度理解如果是安全可控的,可以复用处于 TIME_WAIT 的套接字为新的连接所用。只适用于连接发起方(C/S 模型中的客户端);对应的 TIME_WAIT 状态的连接创建时间超过 1 秒才可以被复用。

使用这个选项,还有一个前提,需要打开对 TCP 时间戳的支持,即net.ipv4.tcp_timestamps=1(默认即为 1)。要知道,TCP 协议也在与时俱进,RFC 1323 中实现了 TCP 拓展规范,以便保证 TCP 的高可用,并引入了新的 TCP 选项,两个 4 字节的时间戳字段,用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳。由于引入了时间戳,我们在前面提到的 2MSL 问题就不复存在了,因为重复的数据包会因为时间戳过期被自然丢弃。

  • 短连接->长连接

参考文章

如何优化高并发TCP链接中产生的大量的TIME_WAIT的状态-腾讯云开发者社区-腾讯云

这篇关于TIME_WAIT的危害的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1077193

相关文章

nginx 504 Gateway Time-out

环境:PHP7.1,NGINX,Mysql 问题描述: 本地写了一个需要执行比较长时间的脚本,放到了php-fpm里面跑。用一个链接调用起这个脚本。发现第一次调用的时候,需要等比较久的时间,但是如果在执行期间再次请求这个链接。第二个请求的链接会返回504。甚至,直接在脚本最开始的地方中断都还是报 504. 但是如果请求其他链接,可以正常请求。 nginx 返回码、、 504 Gateway

Windows 内核驱动无法使用 __DATA__、__TIME__、__TIMESTAMP__ 解决方法

项目 -> 属性 -> Driver Settings -> Driver Model -> Allow Date, Time and Timestamp -> Yes。 感谢单总的解答和这篇文章:https://developercommunity.visualstudio.com/content/problem/186922/-timestamp-macro-not-defined-in-r

OSS报错The difference between the request time and the current time is too large

目录 一、问题描述二、问题原因三、解决方法 一、问题描述 文件上传阿里云 OSS 报错: The difference between the request time and the current time is too large 二、问题原因 请求发起的时间超过 OSS 服务器当前时间 15 分钟,OSS 判定该请求无效,返回报错。 三、解决方法 OSS

关于面试经常被问到的socket的TIME_WAIT状态的原因及解决办法和避免的办法

一查看现在time_wait的数量及浅析          netstat -an | grep TIME_WAIT | wc -l  发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决,在 /etc/sysctl.conf中加入          net.ipv4.tcp_tw_recycle = 1    (表示开启TCP连接中TIME-WAIT sockets的快速回

C++之std::condition_variable::wait_for

std::condition_variable::wait_for 是 C++11 引入的条件变量的一部分,用于在一定时间内等待通知。它是 std::condition_variable 类的成员函数之一,可以使线程在等待某条件变为真时,最多等待指定的时间段。 使用方法 在 std::condition_variable 中,wait_for 的主要形式如下: cpp template

Mysql中CURRENT_TIMESTAMP,CURRENT_DATE,CURRENT_TIME,now(),sysdate()各项值的区别

CURRENT_TIMESTAMP,CURRENT_DATE,CURRENT_TIME,now(),sysdate()各项值的区别,我们可以通过在终端下,查看结果就能知道: SELECT CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, now(), sysdate(); 比如我们要对某表插入数据,这个表add_time字段是datetime类

poll_wait新的理解

应用程序使用 select() 或 poll() 调用设备驱动程序的 poll() 函数,该函数把输入输出复用处理的等待队列追加到由内核管理的进程的 poll_table()上。此时,poll() 函数上传递的参数包括含有设备文件信息的 struct file 结构体的指针参数 struct file *filp ,以及追加到设备驱动上的 poll_table结构体指针参数 poll_table

wait_event_interruptible和wake_up_interruptible

wait_event_interruptible和wake_up_interruptible这两个是内核定义的宏 原型: wait_event_interruptible(wq, condition) wake_up_interruptible(x) wq:等待队列,当后面的条件不成立则进程进入休眠 condition:判断条件 ,0或非0值 x: 等待队列,要唤醒的等待队列,

论文浅读之Mamba: Linear-Time Sequence Modeling with Selective State Spaces

介绍 这篇论文提出了一种新型的"选择性状态空间模型"(Selective State Space Model, S6)来解决之前结构化状态空间模型(SSM)在离散且信息密集的数据(如文本)上效果较差的问题。 Mamba 在语言处理、基因组学和音频分析等领域的应用中表现出色。其创新的模型采用了线性时间序列建模架构,结合了选择性状态空间,能够在语言、音频和基因组学等不同模式中提供卓越的性能。这种突破

【读论文】Learning perturbations to explain time series predictions

文章目录 Abstract1. Introduction2. Background Work3. Method4. Experiments4.1 Hidden Markov model experiment4.2 MIMIC-III experiment 5. ConclusionReferences 论文地址:Learning Perturbations to Explain