端口耗尽才是根本原因,需三步确认:查ss -s中TIME_WAIT占比与端口范围是否逼近、dmesg确认内核是否丢弃连接、比对错误日志与TIME_WAIT峰值是否同步,并排除conntrack和FD耗尽干扰。

TIME_WAIT堆积本身不会导致无法发起新请求,真正卡住的是本地临时端口耗尽;排查必须聚焦“端口是否真不够用”,而不是数TIME_WAIT有多少个。
怎么确认是端口耗尽而非其他问题
看到connect: cannot assign requested address错误时,先别改参数。执行这三行命令,缺一不可:
-
ss -s | grep -E "(timewait|inuse)"—— 看timewait数量和inuse总数 -
cat /proc/sys/net/ipv4/ip_local_port_range—— 查当前可用端口范围(比如32768 60999,共约28K) -
ss -tan state time-wait | wc -l—— 精确统计TIME_WAIT连接数
只有当TIME_WAIT数 ≥ 可用端口上限 × 0.9,且错误日志与之时间同步,才说明是端口真不够了。如果inuse远低于max、或TIME_WAIT只有几千,那大概率是ulimit -n(文件描述符)、conntrack表满、或上游服务拒绝连接,不是TIME_WAIT的问题。
为什么ss -ant | grep TIME_WAIT | wc -l不准
这个命令会漏掉被内核回收但尚未从/proc/net/tcp中清除的条目,也包含非本机发起的连接(比如NAT后的真实客户端)。更可靠的方式是:
- 用
ss -s看汇总值,它来自内核socket计数器,实时准确 - 用
awk '/^TCP:/ {print $6}' /proc/net/sockstat读取sockstat里的time-wait字段,和ss -s结果一致 - 避免用
netstat:它依赖/proc/net目录扫描,高并发下性能差、结果滞后
另外,ss -tan state time-wait默认只显示IPv4,若服务启用了IPv6,需加-6参数补全统计。
怎么快速定位是哪个进程在狂建短连接
先锁定高危端口段:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
-
ss -tan state time-wait | awk '{print $4}' | cut -d: -f2 | sort | uniq -c | sort -nr | head -5—— 看哪些本地端口出现最多
再找对应进程:
-
ss -tunap | grep ':(把' 替换成上一步查出的高频端口) - 若看不到PID(权限不足),用
sudo ss -tunap;若仍为空,说明该连接已关闭但TIME_WAIT还在,此时要查历史调用方 - 对可疑进程,用
lsof -p看它当前活跃连接数,再结合-iTCP -n | grep ESTABLISHED | wc -l strace -p抓新建连接行为-e trace=connect
常见肇事者:未复用requests.Session()的Python脚本、PHP里直连API的curl_exec()、Node.js里没配agent的http.request()。
为什么改tcp_fin_timeout没用还可能有害
tcp_fin_timeout控制的是FIN_WAIT_2状态超时,和TIME_WAIT完全无关。Linux内核硬编码TIME_WAIT为2MSL(通常60秒),没有任何运行时参数能缩短它。
- 设
tcp_fin_timeout = 10只会让主动关闭方更快进入TIME_WAIT,反而加速端口消耗 - 它不减少TIME_WAIT数量,只改变进入该状态前的等待节奏
- 过小的值可能导致对方FIN丢失后无法重传,连接异常中断
真正有效的参数只有三个:tcp_tw_reuse = 1(需tcp_timestamps = 1)、ip_local_port_range = 1024 65535、tcp_max_tw_buckets = 200000。其他都是干扰项。
最易被忽略的一点:TIME_WAIT堆积的位置取决于谁先发FIN。如果问题出现在你这台机器,说明它是主动关闭方——这时候该优化的不是内核,而是让调用方(比如前端、上游服务)改用长连接,或者把关闭动作交给客户端做。硬调参数只是把压力转嫁给别人。










