TIME_WAIT回收失败表现为新建连接报错且内核日志出现“time wait bucket table overflow”,需同步分析ss -s与dmesg,确认是否真因桶溢出导致静默丢包,而非单纯数量多。

TIME_WAIT 回收失败不是内核“卡住”,而是端口耗尽或桶溢出导致新连接被静默丢弃;排查必须从 ss -s 和 dmesg 同步入手,不能只看数量。
确认是否真发生了回收失败,而非单纯数量多
大量 TIME_WAIT 本身不等于故障。真正失败的表现是新建连接报错,且与内核资源告警同步出现:
- 执行
ss -s,重点看timewait行数字是否接近或超过ip_local_port_range差值(如cat /proc/sys/net/ipv4/ip_local_port_range输出32768 60999→ 约 28232 个可用端口) - 立刻查内核日志:
dmesg | grep "time wait bucket"或grep "TCP: time wait bucket table overflow" /var/log/kern.log。出现该日志,说明内核已开始强制销毁新关闭的连接,直接发 RST,这就是回收失败的铁证 - 检查应用错误日志是否在相同时间点密集出现
connect: cannot assign requested address或Connection reset by peer
定位短连接源头:用 ss 追 IP+端口组合
高频短连接必然体现在客户端 IP 和目标服务端口的高度集中。用以下命令快速聚焦:
-
ss -tan state time-wait | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10→ 查看哪些远端 IP 占了最多 TIME_WAIT -
ss -tan state time-wait | awk '{print $5}' | cut -d: -f2 | sort | uniq -c | sort -nr | head -5→ 查看连向哪些目标端口最频繁(如全是 :8080,大概率是后端 HTTP 调用) - 若结果集中在少数几个内网 IP(如 10.3.2.67),问题就在调用方代码或代理配置;若分散但量大,可能是爬虫、监控探针或未节流的 SDK 调用
验证 tcp_tw_reuse 是否真正生效
很多人开了 net.ipv4.tcp_tw_reuse = 1 却没效果,根本原因是依赖条件不满足:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 必须同时启用
net.ipv4.tcp_timestamps = 1(现代内核默认开,但旧配置可能关;务必显式写入/etc/sysctl.conf并sysctl -p) -
tcp_tw_reuse只对 outbound 连接有效 —— 即本机作为客户端发起的连接;服务端监听侧的 TIME_WAIT 不走这条路 - 它只复用“空闲超 1 秒”的 TIME_WAIT socket,且要求时间戳严格递增;NAT 环境下若客户端时间不同步或复用过快,仍可能被拒绝
- 验证方式:压测中持续运行
ss -tan state time-wait | wc -l,开启前后对比是否稳定在ip_local_port_range的 30% 以内(如从 25000 降到 6000)
绕过回收失败的临时兜底操作
当线上已触发 bucket overflow,参数调整来不及生效时,可快速缓解:
- 临时扩大桶上限(治标):
sysctl -w net.ipv4.tcp_max_tw_buckets=200000,避免内核静默丢包 - 立即释放部分端口(仅限紧急):
ss -ant state time-wait | head -1000 | awk '{print $4}' | xargs -I{} sh -c 'echo {} | cut -d: -f2 | xargs -I{} ss -K dst :{}'(慎用,ss -K会强制 kill 连接,仅用于已确认无业务影响的测试环境) - 更安全的做法是切流:让部分流量走另一台未满载的实例,给当前节点喘息窗口
真正难的不是改参数,而是区分清楚:这个 TIME_WAIT 是你主动发起的(客户端行为),还是别人连你产生的(服务端行为)。前者靠 tcp_tw_reuse + 连接池解决,后者得靠让对方 Keep-Alive 或把关闭动作交还给调用方 —— 混淆这两者,所有优化都会打偏。










