CLOSE_WAIT 堆积主因是应用未调用 close(),导致对端关闭后连接卡在此状态;排查需用 ss/lsof 查真实状态,结合超时配置与抓包验证连接是否空转。

连接数堆积不是因为“限制”本身,而是超时时间过长让连接卡在 ESTABLISHED 或 CLOSE_WAIT 状态迟迟不释放,最终耗尽可用连接资源。排查关键不是看配置里写了多少 limit,而是验证连接是否真在“空转不走”。
确认连接是否真实堆积
别猜,先用系统命令看真实连接状态:
- 查当前到后端的真实活跃连接:ss -tn state established '( dport = :8080 )' | wc -l(把 8080 换成你的后端端口)
- 对比理论值:比如 upstream keepalive 32 × worker_processes 4 = 最多 128 个空闲长连;若实际查出 500+,说明连接没回收
- 看 TIME_WAIT 是否泛滥:ss -s | grep -i time_wait;超过 3 万就可能挤占本地端口池
定位哪类超时在作怪
不同阶段超时对应不同日志关键词和响应码,直接决定排查方向:
- 504 Bad Gateway + 日志含 while reading response header from upstream → 重点查 proxy_read_timeout(等后端响应太久)
- 504 + 日志含 while connecting to upstream → 查 proxy_connect_timeout(建连慢,可能是后端负载高或网络抖动)
- 502 Bad Gateway + 日志含 Connection refused 或 Connection reset → 不是超时,是后端已不可达,但 Nginx 还在尝试复用旧连接
- 大量 408 Request Timeout → 客户端发请求太慢,查 client_header_timeout 和 client_body_timeout
检查超时参数是否协同错位
单个参数调小没用,必须两端对齐、分层匹配:
- Nginx 的 keepalive_timeout(如设 60s)必须 小于 后端的空闲关闭时间(如 Tomcat 的
connectionTimeout=90s),否则后端先断,Nginx 还在往死连接上发数据 - proxy_read_timeout 应略大于后端最长业务耗时(例如后端平均响应 8s,设 20–30s),但不能远高于它(如设 300s)
- 长轮询场景下,keepalive_requests 建议设为 2–5,避免一个连接反复用上百次,拖住资源
验证连接行为是否异常
抓包看连接到底在干什么:
- 执行 tcpdump -i any host 192.168.1.10 port 8080 -c 20(替换目标 IP),观察是否有连接建立后数分钟无任何数据交互却仍保持 ESTABLISHED
- 配合 netstat -anp | grep :8080 | grep ESTABLISHED | wc -l 在后端机器上同步比对,确认堆积是发生在 Nginx 侧还是后端侧
- 开启 Nginx debug 日志(需编译含 --with-debug),搜 keepalive reuse 和 close connection,看连接释放时机是否符合预期











