核心思路是让系统稳住、复用time_wait而非消灭它;需协同调优tcp_max_tw_buckets、tcp_tw_reuse、tcp_timestamps、ip_local_port_range四项内核参数,并配合upstream keepalive与http/1.1配置。

核心思路不是“消灭 TIME_WAIT”,而是让系统能稳住它、复用它、不被它卡死。Nginx 作为反向代理,每秒发起大量 outbound 连接,短连接场景下极易在本机堆积数万 TIME_WAIT,直接导致“Cannot assign requested address”或偶发 502/504,而 CPU 和内存却看起来一切正常。
先确认是不是真问题
别一看到 TIME_WAIT 多就急着改参数。先看内核有没有真的“扛不住”:
- 运行 netstat -s | grep -i "time.*wait.*bucket\|pruned",如果持续出现 time wait bucket table overflow,说明已触顶,tcp_max_tw_buckets 不够用了
- 用 ss -tan state time-wait | wc -l 多次采样(比如每 10 秒一次,持续 2 分钟),取 95 分位值——这才是你真实需要应对的峰值,不是瞬时最大值
- 同时查 ss -s 输出里的 fin-wait-2 和 time-wait 行,对比调优前后趋势,才能判断效果
必须协同生效的四项关键内核参数
单独调任何一个都收效甚微,四者缺一不可:
- net.ipv4.tcp_max_tw_buckets:设为实测峰值的 1.8–2 倍。例如采样得 95 分位是 12 万,建议设为 262144(256K);高并发网关可设到 524288 或 100 万,但前提是端口池够大
- net.ipv4.tcp_tw_reuse = 1:允许 Nginx 主动发起新请求时,复用处于 TIME_WAIT 的本地端口。这是缓解堆积最直接有效的机制
- net.ipv4.tcp_timestamps = 1:tcp_tw_reuse 的硬性前提,用于防止旧包混淆。现代内核默认开启,但建议显式写入配置
- net.ipv4.ip_local_port_range = 1024 65535:把可用临时端口从默认的约 28K 扩到近 64K,否则再大的 tcp_max_tw_buckets 也无端口可用
配合 fin_timeout 缩短“悬停”时间
tcp_fin_timeout 不影响 TIME_WAIT 本身(那是 2MSL 决定的),但它控制 Nginx 作为客户端时,在 FIN_WAIT_2 状态最多等多久。这个状态卡住也会占 socket 和 fd:
- 默认 60 秒太保守,建议设为 30(兼顾稳定性与释放速度)
- 不推荐低于 15 秒,弱网或后端响应慢时易误杀连接
- 注意:它只对 Nginx 主动关闭的连接生效(即 upstream 调用),对客户端断连无效
别忘了上层配套:Nginx 自身的 keepalive 配置
内核调优是兜底,真正减少 TIME_WAIT 生成,靠的是少建连、少断连:
- upstream 块中加 keepalive 128(按后端单实例并发 × 0.7 设置),并配 keepalive_timeout 30s
- 务必启用 proxy_http_version 1.1 和 proxy_set_header Connection '',否则 keepalive 不生效
- 客户端侧也别忽略:适当调高 keepalive_timeout 和 keepalive_requests,减少前端频繁重连











