TCP TIME_WAIT 状态的作用和问题是什么?
答案:TIME_WAIT 是主动关闭方在四次挥手最后发送 ACK 后进入的等待状态,持续 2MSL,核心作用是保证连接可靠终止和防止旧报文干扰新连接
主动关闭方发送最后一个 ACK 后不能直接关闭,必须等待 2MSL(最大报文生存时间,Linux 默认 60 秒)。这段等待有两个目的:
第一,兜底最后的 ACK。 如果这个 ACK 丢了,对端会重传 FIN,TIME_WAIT 状态下还能重发 ACK 响应。没有这个等待,ACK 丢失后对端永远收不到确认,连接无法正常关闭。
第二,让网络中的残留报文过期。 同一个四元组(源IP、源端口、目的IP、目的端口)可能很快建立新连接,旧连接的延迟报文如果还没消失,会被新连接误收。等 2MSL 后这些报文必然被丢弃,不会串扰。
TIME_WAIT 带来的实际问题
高并发短连接场景下,大量连接同时处于 TIME_WAIT,会导致端口耗尽。客户端可用端口约 6 万个,每个 TIME_WAIT 占一个,当并发远超这个数,新连接报 "address already in use"。
服务端主动关闭连接时问题更突出。HTTP/1.0 默认 connection: close,服务端每次响应后主动关连接,短时间积累大量 TIME_WAIT。
怎么解决
实际工程中常用三种手段配合:
开启 tcp_tw_reuse: 允许将 TIME_WAIT 状态的连接端口分配给新连接,前提是开启了 TCP 时间戳(tcp_timestamps=1),用时间戳区分新旧连接,比单纯缩短等待更安全。
用长连接和连接池: 根本思路是减少连接的频繁创建和销毁。HTTP/1.1 默认 keep-alive,数据库连接池复用连接,都是这个逻辑。
扩大端口范围: 调整 ip_local_port_range 到 "1024 65535",治标不治本但能缓解。
bash# Linux 常用配置 sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_timestamps=1 sysctl -w net.ipv4.ip_local_port_range="1024 65535"
注意 tcp_tw_recycle 在 NAT 环境下会导致连接失败,Linux 4.12 后已移除该参数,不要用。
面试追问
为什么是 2MSL 而不是 1MSL? ACK 最多存活 1MSL 到达对端,对端重传的 FIN 也最多存活 1MSL 回来,加起来恰好 2MSL,覆盖了两个方向的最坏情况。
服务端出现大量 TIME_WAIT 说明什么? 说明服务端在主动关闭连接。检查是否 HTTP 响应头缺了 keep-alive,或者业务逻辑在用完连接后主动 close 而非复用。
客户端出现大量 TIME_WAIT 呢? 客户端用短连接高频请求服务端,每次自己主动关连接。排查是否可以用连接池或长连接替代。