写点什么

为什么 TCP 协议有 TIME_WAIT 状态

  • 2020-03-20
  • 本文字数:3661 字

    阅读完需:约 12 分钟

为什么 TCP 协议有 TIME_WAIT 状态

为什么这么设计(Why’s THE Design)是一系列关于计算机领域中程序设计决策的文章,我们在这个系列的每一篇文章中都会提出一个具体的问题并从不同的角度讨论这种设计的优缺点、对具体实现造成的影响。


在这个系列前面的文章中,我们已经多次讨论 TCP 协议的设计原理,其中包括 TCP 协议的 三次握手流量控制和重传机制最大数据段 以及 粘包 等问题。本文将继续分析 TCP 协议的实现细节,今天要分析的问题是为什么 TCP 协议需要 TIME_WAIT 状态以及该状态的作用究竟是什么。


TCP 协议中包含 11 种不同的状态,TCP 连接会根据发送或者接收到的消息转换状态,如下图所示的状态机展示了所有可能的转换,其中不仅包含了正常情况下的状态转换过程,还包含了异常状态下的状态转换:



图 1 - TCP 协议状态


使用 TCP 协议通信的双方会在关闭连接时触发 TIME_WAIT 状态,关闭连接的操作其实是告诉通信的另一方自己没有需要发送的数据,但是它仍然保持了接收对方数据的能力,一个常见的关闭连接过程如下1


  1. 当客户端没有待发送的数据时,它会向服务端发送 FIN 消息,发送消息后会进入 FIN_WAIT_1 状态;

  2. 服务端接收到客户端的 FIN 消息后,会进入 CLOSE_WAIT 状态并向客户端发送 ACK 消息,客户端接收到 ACK 消息时会进入 FIN_WAIT_2 状态;

  3. 当服务端没有待发送的数据时,服务端会向客户端发送 FIN 消息;

  4. 客户端接收到 FIN 消息后,会进入 TIME_WAIT 状态并向服务端发送 ACK 消息,服务端收到后会进入 CLOSED 状态;

  5. 客户端等待两个最大数据段生命周期(Maximum segment lifetime,MSL)2的时间后也会进入 CLOSED 状态;



图 2 - TCP 关闭连接的过程


从上述过程中,我们会发现 TIME_WAIT 仅在主动断开连接的一方出现,被动断开连接的一方会直接进入 CLOSED 状态,进入 TIME_WAIT 的客户端需要等待 2 MSL 才可以真正关闭连接。TCP 协议需要 TIME_WAIT 状态的原因和客户端需要等待两个 MSL 不能直接进入 CLOSED 状态的原因是一样的3


  • 防止延迟的数据段被其他使用相同源地址、源端口、目的地址以及目的端口的 TCP 连接收到;

  • 保证 TCP 连接的远程被正确关闭,即等待被动关闭连接的一方收到 FIN 对应的 ACK 消息;


上述两个原因都相对比较简单,我们来展开介绍这两个原因背后可能存在的一些问题。

阻止延迟数据段

每一个 TCP 数据段都包含唯一的序列号,这个序列号能够保证 TCP 协议的可靠性和顺序性,在不考虑序列号溢出归零的情况下,序列号唯一是 TCP 协议中的重要约定,一旦违反了这条规则,就可能造成令人困惑的现象和结果。为了保证新 TCP 连接的数据段不会与还在网络中传输的历史连接的数据段重复,TCP 连接在分配新的序列号之前需要至少静默数据段在网络中能够存活的最长时间,即 MSL4


To be sure that a TCP does not create a segment that carries a sequence number which may be duplicated by an old segment remaining in the network, the TCP must keep quiet for a maximum segment lifetime (MSL) before assigning any sequence numbers upon starting up or recovering from a crash in which memory of sequence numbers in use was lost.



图 3 - TIME-WAIT 较短导致的数据段延迟接收


在如上图所示的 TCP 连接中,服务端发送的 SEQ = 301 消息由于网络延迟直到 TCP 连接关闭后也没有收到;当使用相同端口号的 TCP 连接被重用后,SEQ = 301 的消息才发送到客户端,然而这个过期的消息却可能被客户端正常接收,这就会带来比较严重的问题,所以我们在调整 TIME_WAIT 策略时要非常谨慎,必须清楚自己在干什么。


RFC 793 中虽然指出了 TCP 连接需要在 TIME_WAIT 中等待 2 倍的 MSL,但是并没有解释清楚这里的两倍是从何而来,比较合理的解释是 — 网络中可能存在来自发起方的数据段,当这些发起方的数据段被服务端处理后又会向客户端发送响应,所以一来一回需要等待 2 倍的时间5


RFC 793 文档将 MSL 的时间设置为 120 秒,即两分钟,然而这并不是一个经过严密推断的数值,而是工程上的选择,如果根据服务历史上的经验要求我们改变操作系统的设置,也是没有任何问题的;实际上,较早版本的 Linux 就开始将 TIME_WAIT 的等待时间 TCP_TIMEWAIT_LEN 设置成 60 秒,以便更快地复用 TCP 连接资源:


C


#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT          * state, about 60 seconds  */
复制代码


在 Linux 上,客户端的可以使用端口号 32,768 ~ 61,000,总共 28,232 个端口号与远程服务器建立连接,应用程序可以在将近 3 万的端口号中任意选择一个:


$ sysctl net.ipv4.ip_local_port_rangenet.ipv4.ip_local_port_range = 32768 61000
复制代码


但是如果主机在过去一分钟时间内创建的 TCP 连接数超过 28,232,那么再创建新的 TCP 连接就会发生错误,也就是说如果我们不调整主机的配置,那么每秒能够建立的最大 TCP 连接数为 ~4706

保证连接关闭

从 RFC 793 对 TIME_WAIT 状态的定义中,我们可以发现该状态的另一个重要作用,等待足够长的时间以确定远程的 TCP 连接接收到了其发出的终止连接消息 FIN 对应的 ACK


TIME-WAIT - represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request.


如果客户端等待的时间不够长,当服务端还没有收到 ACK 消息时,客户端就重新与服务端建立 TCP 连接就会造成以下问题 — 服务端因为没有收到 ACK 消息,所以仍然认为当前连接是合法的,客户端重新发送 SYN 消息请求握手时会收到服务端的 RST 消息,连接建立的过程就会被终止。



图 4 - TIME-WAIT 较短导致的握手终止


在默认情况下,如果客户端等待足够长的时间就会遇到以下两种情况:


  1. 服务端正常收到了 ACK 消息并关闭当前 TCP 连接;

  2. 服务端没有收到 ACK 消息,重新发送 FIN 关闭连接并等待新的 ACK 消息;


只要客户端等待 2 MSL 的时间,客户端和服务端之间的连接就会正常关闭,新创建的 TCP 连接收到影响的概率也微乎其微,保证了数据传输的可靠性。

总结

在某些场景下,60 秒的等待销毁时间确实是难以接受的,例如:高并发的压力测试。当我们通过并发请求测试远程服务的吞吐量和延迟时,本地就可能产生大量处于 TIME_WAIT 状态的 TCP 连接,在 macOS 上可以使用如下所示的命令查看活跃的连接:


$ netstat -tanActive Internet connections (including servers)Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)tcp4       0      0  192.168.50.109.51284   47.95.49.174.443       TIME_WAITtcp4       0      0  192.168.50.109.51275   47.95.49.174.443       TIME_WAIT...tcp4       0      0  192.168.50.109.51273   203.107.32.116.443     TIME_WAITtcp4       0      0  192.168.50.109.51293   203.107.32.116.443     TIME_WAITtcp4       0      0  192.168.50.109.51297   203.107.32.116.443     TIME_WAIT...
复制代码


当我们在主机上通过几千个并发来测试服务器的压力时,这些用于压力测试的连接会迅速消耗主机上的 TCP 连接资源,几乎所有的 TCP 都会处于 TIME_WAIT 状态等待销毁。如果我们真遇到不得不处理单机上的 TIME_WAIT 状态的时候,那么可以通过以下几种方法处理:


  1. 使用 SO_LINGER 选项并设置暂存时间 l_linger 为 0,在这时如果我们关闭 TCP 连接,内核就会直接丢弃缓冲区中的全部数据并向服务端发送 RST 消息直接终止当前的连接7

  2. 使用 net.ipv4.tcp_tw_reuse 选项,通过 TCP 的时间戳选项允许内核重用处于 TIME_WAIT 状态的 TCP 连接8

  3. 修改 net.ipv4.ip_local_port_range 选项中的可用端口范围,增加可同时存在的 TCP 连接数上限;


需要注意的是,另一个常见的 TCP 配置项 net.ipv4.tcp_tw_recycle 已经在 Linux 4.12 中移除9,所以我们不能再通过该配置解决 TIME_WAIT 设计带来的问题。


TCP 的 TIME_WAIT 状态有着非常重要的作用,它是保证 TCP 协议可靠性不可缺失的设计,如果能通过加机器解决的话就尽量加机器,如果不能解决的话,我们就需要理解其背后的设计原理并尽可能避免修改默认的配置,就像 Linux 手册中说的一样,在修改这些配置时应该咨询技术专家的建议;在这里,我们再重新回顾一下 TCP 协议中 TIME_WAIT 状态存在的原因,如果客户端等待的时间不够长,那么使用相同端口号重新与远程建立连接时会造成以下问题:


  • 因为数据段的网络传输时间不确定,所以可能会收到上一次 TCP 连接中未被收到的数据段;

  • 因为客户端发出的 ACK 可能还没有被服务端接收,服务端可能还处于 LAST_ACK 状态,所以它会回复 RST 消息终止新连接的建立;


TIME_WAIT 状态是 TCP 与不确定的网络延迟斗争的结果,而不确定性是 TCP 协议在保证可靠这条路的最大阻碍。到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:


  • net.ipv4.tcp_tw_reuse 配置如何通过时间戳保证重用 TCP 连接的相对安全?

  • net.ipv4.tcp_tw_recycle 配置为什么被 Linux 从协议栈中移除?


本文转载 Draveness 技术网站。


原文链接:https://draveness.me/whys-the-design-tcp-time-wait


2020-03-20 21:291065

评论

发布
暂无评论
  • 自助洗车机洗车怎么收费和付费

    一般情况下,自助洗车机洗车都是按时计费的,也就是说洗的越快费用就越低,洗的越久费用也会越高。不过根据广大车主的洗车时间来看,大多都是付了8-15元左右,洗车时间大多也都在10-20分钟这样。

    2022-06-15

  • 12|如何自动检查业务真实的健康状态?

    这节课,我会首先带你学习 Pod 的状态机制,然后通过示例应用,进一步介绍怎么为工作负载配置健康检查。

    2023-01-04

  • Android C++ 系列:Linux 文件 IO 操作 (二)

    本文介绍了read/write的系统调用,以及阻塞、非阻塞相关的概念以及配置方式,等待超时方式。还介绍了lseek、fcntl、ioctl文件操作相关的系统调用。

    2021-11-18

  • TCP 面试相关总结

    1)主机A发送标志syn=1,随机产生seq =1234567的数据包到服务器,主机B由syn=1知道,A要求建立连接; 此时状态A为SYN_SENT,B为LISTEN

    2021-11-11

  • 深入了解瓴羊 Quick BI,对于商业智能 BI 发展情况更好分析

    企业想要发展的速度更加快速,企业的数字化转型已经成为了不可以忽视的一部分趋势。而根据各种的数据统计便可以注意到,整体的数据分析过程中,行业的各方面的发展则会带来更好的状态,所以涉及到的一些基本的信息情况确实都应该格外认真的考虑。

    2022-11-30

  • 极客时间运维进阶训练营第九周作业

    极客时间运维进阶训练营第九周作业

    2022-12-26

  • 设计微博系统中“微博评论”的高性能高可用计算架构

    评论微博和看微博的情况差不多,因此我们假设一条微博平均有100人评论,则评论微博的次数为:

    2022-05-11

  • 入职字节跳动那一天,我哭了(蘑菇街被裁,奋战 7 个月拿下 offer)

    先说一下个人情况,18届应届生,通过校招进入到了蘑菇街,然后一待就待了差不多2年多的时间,可惜的是今年4月份受疫情影响遇到了大裁员,而他也是其中一员。好在早有预感,提前做了准备,之前一直想去字节跳动,年前就已经在做准备了,这场持久战拉得很长,也

    2021-11-09

  • TechBits | TCP 使用 WireShark 进行抓包

    我还记得有一次在工作中遇到一个网络情况:我通过调用第三方提供的接口,完成了一个采集任务。过来一段时间,采集数据出现了问题,我开始排除,发现请求对方接口出现一种现象:有的时候连接会超时,有的时候又不会超时,导致采集出现问题。但是,出现这个问题

    2023-03-20

  • 分布式爬虫

    2022-09-08

  • [译]TIME_WAIT 及其对协议和可伸缩客户端服务器系统的设计实现

    当构建基于 TCP 的 C/S系统的时候,非常容易犯一些简单的错误,这些错误会严重限制系统的可伸缩性。其中之一就是对 TIME_WAIT 状态疏于考虑。在此博客文章中,我将说明 TIME_WAIT 存在的原因、它可能引起的问题、该如何解决它以及何时不应该考虑解决它。

    2023-03-15

  • 定位防火墙(一):传输层的对比分析

    无论防火墙有多么神秘,它本质上是一种网络设备。既然是网络设备,那么它必然同样遵循我们知道的技术原理和网络规范。所以,防火墙的踪迹,虽然表面上给人一种虚无缥缈的感觉,但从理论上说,总是有迹可循的。

    2022-01-21

  • 深入了解 HTTP 协议

    2022-09-08

  • 17|巨人的肩膀:HTTP 协议与 Go 标准库原理

    这节课,我们来看看当数据包到达对端服务器之后,操作系统和硬件会如何处理数据包。

    2022-11-17

  • NFT 加密钱包交易系统开发搭建技术

    NFT钱包是一种加密货币钱包,它可以帮助用户管理和交易NFT,以及保证用户的资产安全。NFT加密钱包交易系统开发询13z李4277森z558,NFT交易平台开发搭建技术。

    2023-04-24

  • Linux 之 ss 命令

    ss是Socket Statistics的缩写。顾名思义,ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容。但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。

    2021-08-12

  • 如何整理自己的前端面试题库

    如果是 HTTP 1.0 版本协议,一般情况下,不支持长连接,因此在每次请求发送完毕之后,TCP 连接即会断开,因此一个 TCP 发送一个 HTTP 请求,但是有一种情况可以将一条 TCP 连接保持在活跃状态,那就是通过 Connection 和 Keep-Alive 首部,在请求头带上 Conn

    2023-02-07

  • 状态机的概念与设计

    一般情况下,状态触发器的数量是有限的,其状态数也是有限的,故称为有限状态机(Finite State Machine,简称为FSM)。状态机中所有触发器的时钟输入端被连接到一个公共时钟脉冲源上,其状态的转换是在同一时钟源的同一脉冲边沿同步进行的,所以它也被称作时

    2023-02-09

  • 项目代码详解

    2022-12-29

  • 在线问题反馈模块实战 (十五)​: 实现在线更新反馈状态功能

    在线问题反馈模块实战教学,等你来白嫖,非常详细,适合新手小白学习。

    2022-10-23

发现更多内容

jenkins接入钉钉api接口自动化测试报告自动发送

霍格沃兹测试开发学社

浅谈Redis的三种集群策略及应用场景

天翼云开发者社区

集群 redis 底层原理

「手撕Vue-CLI」拷贝模板

EquatorCoco

JavaScript vue.js 前端

「布道师系列文章」众安保险王凯解析 Kafka 网络通信

AutoMQ

kafka java

搭建高可用k8s

不在线第一只蜗牛

Kubernetes 容器化 Linux 运维

SD-WAN是怎样帮助企业业务开展的?

Ogcloud

SD-WAN 企业组网 SD-WAN组网 SD-WAN服务商 SDWAN

网络安全等级保护测评师定义以及主要工作任务是什么?

行云管家

网络安全 等保测评师

[图数据库]Neo4j中心性算法-以红楼梦为例

alexgaoyh

neo4j 图算法 紧密中心度 红楼梦 中心度算法

Linux 三剑客之 awk:最强大的经典数据处理工具

测吧(北京)科技有限公司

测试

Linux 三剑客之 sed:数据的流式编辑

测吧(北京)科技有限公司

测试

MySQL Shell 使用指南

Simon

MySQL mysqlshell

欧特克汽车创新论坛:一汽大众和东研智慧展示最新数字化方案

E科讯

这是我的新名片,望您惠存!

通明湖

百度文库与龙腾出行达成战略合作,首创「VAIP智能空间」,重构商旅人士工作流

Geek_2d6073

为什么SD-WAN比MPLS更适合中小型企业

Ogcloud

SD-WAN 企业组网 SD-WAN组网 SD-WAN服务商 SDWAN

Linux 环境配置指南

测吧(北京)科技有限公司

测试

网络安全专用产品销售许可证查询的几种方式你知道吗?

行云管家

网络安全 堡垒机 销售许可证

Jenkins源代码管理+接入钉钉api发送接口自动化测试报告

测试人

软件测试 jenkins

英伟达市值超越苹果;ChatGPT、Perplexity、Claude 同时大崩溃丨 RTE 开发者日报 Vol.220

声网

AutoMQ 生态集成 Ceph

AutoMQ

kafka java

高德面试:为什么Map不能插入null?

王磊

Java

Linux 三剑客之 grep

测吧(北京)科技有限公司

测试

今天的加密货币市场走势和相关信息

dappweb

清华博士带你掌握 Llama 大模型 40 节课助你涨薪 120%

OSCTraining

llama Llama3

企业数字化转型的主要方面有哪些?

优秀

数字化转型

jenkins源代码管理+接入钉钉api发送接口自动化测试报告

测吧(北京)科技有限公司

测试

怎么画ER关系图?这个在线ER图软件值得推荐!

彭宏豪95

职场 ER图 在线白板 办公软件 绘图软件

【玩转IPD】未来5年,只有这种产品团队才能开启上帝视角

快乐非自愿限量之名

产品运营 IPD

AMD 和英伟达 COMPUTEX 2024 发布亮点

GPU算力

gpu 英伟达 芯片 AMD #人工智能

为什么 TCP 协议有 TIME_WAIT 状态_文化 & 方法_Draveness_InfoQ精选文章