首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164…
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca…
一. 前言
之前在 juejin.cn/post/709793… 这篇文章中简单讲了一下连接的变化 , 这一篇来看一下这个数据在实际业务中有什么作用,以及实际的案例 :
TIME_WAIT 产生的时机
TIME_WAIT 是指在 TCP 连接关闭后,为了保证数据的可靠传输,TCP 协议需要等待一段时间(通常是 2MSL,即两倍的最大报文段生存时间),以确保对方接收到了最后一个 ACK 报文段,同时也为了防止已经失效的连接请求报文段被传到下一个连接中。在这段等待时间内,TCP 连接处于 TIME_WAIT 状态。
主要原因 : 为了避免网络中已经失效的连接请求报文段被传到下一个连接中,从而导致数据的错误传输。
- 当一个 TCP 连接关闭后,客户端和服务端都会发送一个 FIN 报文段,表示关闭连接。
- 如果客户端发送的 FIN 报文段没有及时到达服务端,而服务端已经开始关闭连接,那么服务端将无法正确的处理客户端发送的 FIN 报文段。
- 如果此时有一个新的连接请求到达服务端,并且该连接的一些数据恰好和客户端发送的 FIN 报文段重复,那么就有可能会导致数据的错误传输。
解决方案: 为了避免这种情况发生,TCP 协议需要等待一段时间,以确保对方接收到了最后一个 ACK 报文段,同时也为了防止已经失效的连接请求报文段被传到下一个连接中。因此,TIME_WAIT 是 TCP 协议为保证数据传输的可靠性而设计的一种等待状态。
二. TIME_WAIT 基础知识
2.1 TIME_WAIT 查询方式
通常在业务中可以使用 netstat 命令来查看系统的网络连接状态:
// 查看当前所有连接的状态,包括 TIME_WAIT 状态
netstat -an
// 查看指定 IP 地址和端口的连接状态
netstat -an | grep [IP]:[port]
// 查看所有状态为 TIME_WAIT 的连接
netstat -an | grep TIME_WAIT
// 查看所有 TIME_WAIT 状态的连接并统计数量
netstat -an | grep TIME_WAIT | wc -l
PS : netstat 命令只能提供实时的连接信息,无法记录历史连接信息,想要更多的历史消息,可以考虑抓包
2.2 TIME_WAIT 会和哪些问题有关
// 系统内核参数可以直接影响到 TIME_WAIT 的状态
- net.ipv4.tcp_fin_timeout : 减少 TIME_WAIT 状态的持续时间
- net.ipv4.tcp_max_tw_buckets : 增加系统允许的 TIME_WAIT 连接数量
// 连接复用
- 如果没有通过连接池等技术进行连接池复用,则连接的创建和关闭次数会直接影响TIME_WAIT的数量
// 应用程序连接配置
- 可以通过调整程序的连接超时时间、连接复用机制等方式来减少连接的创建和关闭次数
// 高并发请求
- 请求并发高的时候,会直接导致 TIME_WAIT 的数量,而且这种数量已经很难通过优化解决了
- 通过负载均衡等方式,可以减少 TIME_WAIT
优化 TIME_WAIT 的方式
- 减少 TCP 连接的建立和关闭次数,避免频繁建立和关闭连接。
- 增加系统的最大端口号范围,确保端口号不会被用尽。
- 调整系统的网络参数,如减小 TIME_WAIT 状态持续时间,增加 TCP 连接的最大数量等。
- 使用连接池,避免频繁创建新连接。
- 提升硬件性能,负载均衡到多台服务器。
三. TIME_WAIT 问题实践
3.1 压测与 TIME_WAIT 的观测
- 影响 : 压测工具通常会模拟大量的并发连接,而由于没有连接池等工具,导致服务器端创建大量的连接
- 避免 : 控制 TIME_WAIT 状态的持续时间和重用规则,从而缓解 TIME_WAIT 对服务器资源的占用
3.2 实践场景
这也是当时首次碰到 TIME_WAIT 的问题,当时一路搞到凌晨2-3点,最终还是通过 TIME_WAIT 的值找到了问题。
背景 :
项目上在系统交付之前,做了一次压测,但是压测的结果一直不理想,远远低于产品的理论值。产品会调用 LDAP (可以理解成一种树形数据库) ,MySQL 等外部特征
具体的分析过程 :
具体的压测数据就不举例了 ,整个过程大概如下 :
// S1 : 首先我们观测的压测值,数值很低, 很不理想
系统中在未进行优化前,会存在很多系统的瓶颈,压测的目的就是为了发现这些瓶颈,同时想办法解决他们。
// S2 : 早期我们在优化代码,尽量减少了数据库的查询
早期的解决方式主要是优化,优化了查询的处理 (其实这里也是在减少连接,一次查询造成的损耗是最大的)
// S3 : 后续优化连接池方案
代码优化完成后 ,选择的方向就是优化连接池,通过优化连接池的参数后,可以减少创建连接的开销
(PS:优化 Mysql连接后一般性能会得到很大的提升)
// S4 : 优化硬件性能
但是到了这阶段,性能其实还是不理想,然后选择试着提升硬件性能。
// S5 : 发现问题
此时就发现,无论如何提升硬件和优化连接,压测能力都没太大提升!
推测是网络带宽是否达到了上限,进行网络排查的时候,发现TIME_WAIT 数一路飙升,当时好像接近2万
// S6 : 排查方式
通过 netstat 获取后,发现一个端口在不断的创建连接。最终进行 DEBUG 后确定由于版本问题LDAP连接池没有生效
总结 : TIME_WAIT 如果过大,但是压测数据又没有达到正常的理论值,可能就是连接池问题
- 连接池可以有效减少 TIME_WAIT 数量
- 优化硬件对 TIME_WAIT 没有提升 (单机存在IO瓶颈,到了一定量CPU性能会下降很多)
四. 相关问题
4.1 TIME_WAIT 会占用一个随机端口数吗
什么是随机端口数?
在TCP协议中,客户端通常会使用一个随机的端口号来与服务器建立连接。
客户端请求服务器的IP地址和端口号,但客户端并不会指定自己使用的端口号,而是由操作系统自动分配一个空闲的临时端口号。
客户端使用这个随机端口号来建立连接,服务器会将响应数据发送到这个端口号,客户端通过这个端口号接收服务器的响应数据
TIME_WAIT 会占用吗?
就像之前看到的,每一个 time_wait 状态,都会占用一个「本地端口」,上限为 65535。
当连接处在 TIME_WAIT 状态时,使用的端口号与关闭连接前的端口号相同,不会占用其他的端口号。
在此状态下,本地端会等待两倍的MSL(Maximum Segment Lifetime,最大报文生存时间)的时间,这个时间通常为几分钟,之后才会释放该端口。如果这个时候新连接使用了这个端口,就可能出现数据混乱或者安全问题。
4.2 TIME_WAIT 占用系统资源
或者说整个系统建立连接的场景下,有哪些占用资源的点 :
- 建立TCP连接时,客户端需要指定目标服务器的IP地址和端口号,这个过程可能需要进行DNS查询和端口扫描等操作,这些操作可能会消耗一些资源
- 短时间内频繁建立和关闭TCP 连接 ,TIME_WAIT 状态连接会占用系统的端口号和内存等资源,从而影响系统的性能
- 随机端口号范围小了,引发端口号竞争 , 临时端口号的竞争可能会导致TCP连接建立失败或者连接超时
4.3 TIME_WAIT 与连接池的关系
使用连接池可以有效地减少连接的创建和关闭次数,从而减少 TIME_WAIT 状态下的连接数量。同时,连接池还可以通过控制连接数量、超时时间等参数,进一步优化连接的使用效率。
但是,如果连接池中存在大量的 TIME_WAIT 状态下的连接,那么连接池的效率可能会受到影响,从而导致系统性能下降。因此,需要通过调整连接池的参数,如最大连接数量、连接超时时间等,来避免 TIME_WAIT 问题的影响。
4.4 TIME_WAIT 与 TCP_SYNC
TCP_SYNC :攻击者利用伪造的 SYN 报文不断向受害者的服务器发送连接请求,但是连接并不能完成三次握手,最终服务器会不断创建半连接,引发系统崩溃。
攻击中,攻击者会大量发送伪造的 SYN 报文,但不回应服务器的 SYN+ACK 报文,从而使服务器不断等待客户端的 ACK 报文,最终导致服务器的连接队列被占满,无法响应正常连接请求。
TIME_WAIT 和 TCP_SYNC 本身没有联系,只是半连接在一定时间后会变成 TIME_WAIT 状态,就可以观测到 TIME_WAIT 数量增多。
总结
小知识点,说不定哪天又可以用上。