TCP TIME_WAIT 过多导致端口耗尽的排查与调优
现象
一台高并发短连接服务(反向代理、压测客户端、批量调用方)运行一段时间后,新建连接开始失败,报错 Cannot assign requested address,但 CPU、内存、带宽都不高,服务端也没有拒绝连接。这时很可能不是对端的问题,而是本机可用的临时端口被 TIME_WAIT 状态的连接占满了。
什么是 TIME_WAIT
TCP 主动关闭连接的一方,在发送最后一个 ACK 后会进入 TIME_WAIT 状态,持续 2MSL(Linux 默认约 60 秒),目的是防止旧连接的延迟报文干扰新连接。在这段时间内,该连接的四元组(源 IP、源端口、目标 IP、目标端口)不能被复用。短连接场景下,每秒新建几千个连接,60 秒就能攒下几万个 TIME_WAIT,而临时端口默认只有约 2.8 万个,很快耗尽。
第一步:确认数量
先看总体分布,再看 TIME_WAIT 数量:
ss -s
ss -tan state time-wait | wc -l
ss -tan | awk '{print $1}' | sort | uniq -c | sort -nr
再看本机临时端口范围和超时时间:
cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/ipv4/tcp_fin_timeout
cat /proc/sys/net/ipv4/tcp_max_tw_buckets
如果 TIME_WAIT 数量接近端口范围上限,基本可以确认是端口耗尽;如果数量不大,就要换方向排查,比如文件描述符、连接数上限或对端限流。
第二步:调优参数(先在测试环境验证)
把下面几项写入 /etc/sysctl.conf,再执行 sysctl -p 生效:
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_max_tw_buckets = 262144
说明三点:第一,tcp_tw_reuse 只对作为客户端主动发起连接的一方有效,且不要在 NAT 环境下随意开启;第二,tcp_fin_timeout 缩短的是 FIN_WAIT2 的等待时间,间接减少堆积;第三,tcp_tw_recycle 已在 Linux 4.12 及之后内核中移除,网上老教程里的这一项不要再加。
第三步:根治要靠减少短连接
参数调优只是争取时间,根治办法是减少新建连接的频率:客户端使用连接池和长连接,复用已有连接;反向代理开启 keep-alive;调用方避免每次请求都新建连接;必要时用多个出口 IP 分摊端口压力。做完后重新跑 ss -tan state time-wait | wc -l 观察,数量应明显回落且不再随时间单调上涨。
小结
排查顺序是:先用 ss -s 和 ss -tan state time-wait | wc -l 确认 TIME_WAIT 规模,再核对 /proc/sys/net/ipv4/ip_local_port_range,最后才是调参和改造连接复用。记住,TIME_WAIT 本身是 TCP 的正常保护机制,调参的目标是让它不再成为瓶颈,而不是把它彻底关掉。
- 点赞
- 收藏
- 关注作者
评论(0)