首页/网络/协议速查/CLOSE_WAIT 堆积排查
TCP 与 UDP54 条

CLOSE_WAIT 堆积排查

对方已发 FIN、本端内核已 ACK,但应用还没调用 close:CLOSE_WAIT 数量只增不减说明连接被应用层泄漏。

协议速查网络更新于 2026-10-13

CLOSE_WAIT 意味着什么

TCP 四次挥手时,如果对方先发 FIN,本端内核会自动回一个 ACK,连接随即进入 CLOSE_WAIT,接下来要等应用程序调用 close 才会发出自己的 FIN。也就是说,这个状态该停留多久完全由应用决定。因此 CLOSE_WAIT 数量只增不减,基本可以断定是应用层没有关闭连接,而不是内核参数或网络问题,调内核参数是南辕北辙。

定位泄漏进程

定位泄漏进程
ss -tan state close-wait | wc -l          # 先看总量,持续增长才是问题
ss -tanp state close-wait | head -20      # 加 -p 看归属进程(需 root)
ss -tan state close-wait | awk '{print $5}' | sort | uniq -c | sort -rn | head   # 按对端聚合,找出泄漏来源
ls /proc/<pid>/fd | wc -l                 # 对照该进程 fd 数量,逼近上限就危险
ulimit -n                                 # 查看进程 fd 上限

输出逐列读法

列含义怎么看
State连接状态,如 CLOSE-WAIT数量平滑而不下降就是泄漏
Recv-Q接收队列里还没被应用读走的字节长期非 0 说明应用卡住没读数据
Send-Q发送队列里还没被确认的字节持续非 0 通常是对端不接收
Local Address:Port本端地址与端口据此判断是哪个服务在泄漏
Peer Address:Port对端地址与端口按对端聚合能定位是哪个上游引起的
users:(...)归属进程与 pid需要 root 权限才显示,是定位根因的关键

常见根因与后果

代码分支遗漏异常路径提前返回,连接没有走到关闭逻辑
连接池不回收借出的连接没归还,或归还时未真正关闭
线程阻塞线程卡在别处,finally 或 defer 迟迟未执行
后果fd 耗尽后新连接直接报 Too many open files,服务整体不可用
修复只能从应用侧入手:给读写设置超时、确保 defer 或 finally 关闭连接、检查连接池归还逻辑。内核参数再调也不会替你调用 close。
如果 CLOSE_WAIT 与大量 TIME_WAIT 同时出现,要分开看:CLOSE_WAIT 是应用程序的问题,TIME_WAIT 是主动关闭方的正常状态,两者处置方式完全不同。

易错点

  • 看到 CLOSE_WAIT 就去调内核网络参数:内核只负责协议栈,close 必须由应用发起,调参不会让数量下降
  • 只处理表面现象(重启服务)而不修代码里的连接关闭逻辑,泄漏会在运行一段时间后原样复现
  • 把 CLOSE_WAIT 当成对端的问题去联系上游:这个状态记录的是本端应用没关连接,责任在本地
  • 监控只盯连接总数不盯 fd 使用率,等真正报 Too many open files 时业务已经整体不可用

数据来源与参考

  • RFC 9293 §3.3.2
  • man 8 ss

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌