前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP TIME_WAIT 过多怎么处理

TCP TIME_WAIT 过多怎么处理

作者头像
恋喵大鲤鱼
发布2024-02-03 08:43:52
1170
发布2024-02-03 08:43:52
举报
文章被收录于专栏:C/C++基础C/C++基础

1.什么是 TCP TIME_WAIT?

TCP 断开连接四次挥手过程中,主动断开连接的一方,在第四次挥手(回复 ACK 报文)后,会进入 TIME_WAIT 状态,等待 2*MSL 后才进入 CLOSE 状态。

RFC793 定义 MSL 为 2 分钟,但实际应用中常用的是30秒,1分钟和2分钟等。Linux 内核通常硬编码为 30 秒。

2.为什么要 TIME_WAIT?

这么做有两个原因:

  • 保证 ACK 重发

如果 ACK 报文丢失,被动断开连接的一方会超时重传 FIN 报文,所以需要等待 2MSL 时间处理重传的 FIN 报文,确保对方接收到确认,正常关闭连接。

  • 丢弃旧连接延迟报文

让旧连接报文从网络中消失,避免新连接收到旧连接的报文。如果不等,释放的端口可能会重新与服务器建立连接,这样依然存活在网络里的旧连接 TCP 报文可能与新连接 TCP 报文冲突,造成数据冲突。

3.TIME_WAIT 过多的影响

如果客户端(主动发起关闭连接)存在大量 TIME_WAIT 状态连接,会占用端口资源,导致新建 TCP 连接出错,报address already in use : connect异常。

如果服务端(主动发起关闭连接)存在大量 TIME_WAIT 状态连接,并不会导致端口资源受限,因为服务端只监听一个端口,而且由于一个四元组唯一确定一个 TCP 连接,因此理论上服务端可以建立很多连接。但是 TCP 连接过多,会占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等

4.解决办法

4.1 调整短连接为长连接

比如 HTTP/1.0 请求与回包中,在 Header 中添加Connection: keep-alive

从 HTTP/1.1 开始, 就默认是开启了 keep-alive,现在大多数浏览器都默认使用 HTTP/1.1,所以 keep-alive 都是默认打开的。

如果要关闭 HTTP Keep-Alive,需要在 HTTP 请求或者响应的 header 里添加 Connection:close 信息,也就是说,只要客户端和服务端任意一方的 HTTP header 中有Connection:close信息,那就无法使用 HTTP 长连接机制。

4.2 调整系统内核参数

修改 /etc/sysctl.conf 文件中的相关配置,然后执行sysctl -p命令使配置生效。

  • 开启复用 net.ipv4.tcp_tw_reuse,默认为 0。

开启后,可以复用处于 TIME_WAIT 的 socket 为新的连接所用。

有一点需要注意的是,tcp_tw_reuse 功能只能用客户端(连接发起方),因为开启了该功能,在调用 connect() 函数时,内核会随机找一个 TIME_WAIT 状态超过 1 秒的连接给新的连接复用。

使用这个选项,还有一个前提,需要打开对 TCP 时间戳的支持,即

代码语言:javascript
复制
net.ipv4.tcp_timestamps=1(默认即为 1)

这个时间戳字段在 TCP 头部的「选项」里,占用 8 个字节。其中第一个 4 字节保存发送该数据包的时间,第二个 4 字节保存最近一次接收到对方数据的时间。

由于引入了时间戳,前面提到的旧连接延迟报文问题就不复存在了,因为重复的报文会因为时间戳过期被自然丢弃。

  • 减小 net.ipv4.tcp_max_tw_buckets。

这个值默认为 18000,当系统中处于 TIME_WAIT 的连接一旦超过这个值时,新的 TIME_WAIT 连接会被立即销毁,并打印警告,这个方法比较暴力。

  • 程序中使用 SO_LINGER。

我们可以通过设置 socket 选项,来设置调用 close 关闭连接行为。

代码语言:javascript
复制
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));

如果 l_onoff 为非 0, 且 l_linger 值为 0,那么调用 close 后,会立该发送一个RST标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了 TIME_WAIT 状态,直接关闭。

这为跨越 TIME_WAIT 状态提供了一个可能,不过是一个非常危险的行为,不值得提倡。

5.小结

TIME_WAIT 是我们的朋友,不要试图避免这个状态,而是应该弄清楚它。

TIME_WAIT 不是 Bug,而是被设计出来的有着非常重要作用的特性,它是保证 TCP 协议可靠性不可缺失的设计。

如果过多的 TIME_WAIT 影响了系统的运行,能通过加机器解决的话就尽量加机器,如果不能解决,我们就需要理解其背后的设计原理并尽可能避免修改默认的配置。

如果服务端要避免过多的 TIME_WAIT 状态的连接,就永远不要主动断开连接,让客户端去断开,由分布在各处的客户端去承受 TIME_WAIT。

参考文献

4.1 TCP 三次握手与四次挥手面试题 - 小林coding 为什么TCP 协议有TIME_WAIT 状态 - 面向信仰编程

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.什么是 TCP TIME_WAIT?
  • 2.为什么要 TIME_WAIT?
  • 3.TIME_WAIT 过多的影响
  • 4.解决办法
    • 4.1 调整短连接为长连接
      • 4.2 调整系统内核参数
      • 5.小结
      • 参考文献
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档