Close_Wait状态连接需Nginx主动调用close()释放,epoll仅通知FIN不自动清理;堆积主因是应用层未及时关闭socket,导致fd耗尽、新连接失败。

在 Nginx 使用 epoll 作为事件驱动模型时,Close_Wait 状态的连接不会被 epoll 自动回收或主动关闭,它完全依赖于应用层(即 Nginx 自身)是否及时调用 close() 或 shutdown()。epoll 只负责通知“对端已关闭连接”(即收到 FIN),但不会替你清理资源。
Close_Wait 是什么,为什么它会堆积?
当客户端发送 FIN 关闭连接,服务端收到后进入 Close_Wait 状态,表示“我已知对方关了,但我还没决定是否关自己这端”。此时 TCP 连接仍占用一个 socket 描述符,且处于半关闭状态。
如果 Nginx(或其上游应用)没有及时调用 close(),这个 socket 就一直卡在 Close_Wait,表现为:
- netstat / ss 中大量
Close_Wait连接; - 文件描述符(fd)缓慢耗尽;
- 新连接建立失败("Too many open files");
- 但 epoll 依然能正常工作——它不感知 Close_Wait,只关心可读/可写/错误事件。
Nginx 如何处理 Close_Wait 连接?
Nginx 本身是主动关闭方还是被动方,决定了 Close_Wait 出现的位置:
- 若 Nginx 是反向代理,后端服务迟迟不发 FIN,Nginx 与后端的连接可能长期处于 Close_Wait(常见于后端进程卡死、未正确关闭 socket);
- 若客户端异常断连(如 App 强退、NAT 超时),而 Nginx 配置了过长的
keepalive_timeout或未启用健康探测,它可能维持着已失效的连接; - Nginx 默认在收到客户端 FIN 后,会在当前请求处理完后尽快 close 自己这一端——但前提是请求能正常结束(比如没有阻塞 upstream、没有长轮询未返回)。
关键配置和缓解手段
以下配置直接影响 Close_Wait 的生命周期:
-
keepalive_timeout 60s;:控制空闲 keepalive 连接的最大存活时间,超时后 Nginx 主动 send FIN,避免连接滞留; -
send_timeout 15s;:向客户端发送响应时,两次写操作间隔超过该值则关闭连接; -
proxy_next_upstream error timeout http_502;+proxy_next_upstream_timeout 10s;:提升后端故障时的连接释放速度; -
reset_timedout_connection on;:对超时的空闲连接直接 reset(RST),跳过 FIN 交互,强制清除状态(适用于无法控制客户端行为的场景); - 确保
worker_connections和系统fs.file-max、ulimit -n匹配,避免因 fd 耗尽掩盖真实问题。
排查与验证建议
定位 Close_Wait 堆积源头比单纯调参更重要:
- 用
ss -tan state close-wait | wc -l统计数量; - 用
ss -tan state close-wait src :80看是来自客户端还是发往后端; - 结合
nginx -T检查所有 timeout 相关指令是否合理; - 检查 upstream 是否存在响应延迟、无 FIN 关闭、或复用连接未正确管理(如 HTTP/1.0 后端未声明 keepalive);
- 开启
error_log ... debug_event;(谨慎使用)可观察连接关闭路径,但生产环境慎开。











