Nginx fd 耗尽主因是长连接复用失效而非并发过高;需验证 ESTABLISHED 连接数与 fd 增长趋势,检查客户端及 upstream 的 keep-alive 配置、响应头 Connection 字段、协议升级头处理是否合规。

看到 Nginx 错误日志反复出现 accept() failed (24: Too many open files),同时连接数不高但 fd 持续上涨,大概率不是总量不够,而是长连接没被复用,导致每个请求都新建 socket、旧连接又迟迟不释放——fd 就这么“悄悄堆满”了。
确认是否真因复用失效导致 fd 累加
别只盯着报错,先验证复用行为是否生效:
- 用
ss -tan state established | wc -l查当前 ESTABLISHED 连接数,再对比worker_processes × worker_connections,若远低于上限却仍报 fd 耗尽,说明连接在“堆积”而非“并发激增” - 执行
lsof -p $(pgrep nginx | head -1) | grep TCP | wc -l,观察一段时间内该 worker 的 fd 数是否持续单向增长(比如每分钟+50),这是典型复用失败信号 - 抓包或查 access_log,看客户端请求头是否带
Connection: keep-alive,响应头是否返回Connection: keep-alive;若响应中频繁出现Connection: close,说明复用链路已被中断
检查客户端到 Nginx 这一段的复用配置
这一段复用由 keepalive_timeout 和 keepalive_requests 控制,缺一不可:
-
keepalive_timeout必须显式设置(默认 65s 不够稳),建议 75–120s;太短(如 5s)会让活跃连接反复断开重连 -
keepalive_requests默认 100,对现代前端(React/Vue 单页加载 30+ 资源)明显不足,应设为 1000–3000 - 确保没有在 location 或 server 块里意外覆盖这两个值,尤其避免写成
keepalive_timeout 0或keepalive_requests 1
排查 Nginx 到后端 upstream 的复用断点
即使客户端连接复用了,若 Nginx 到后端仍是短连接,fd 同样会爆炸:
- upstream 块必须启用
keepalive N(如keepalive 32),且 N 不为 0;只配proxy_http_version 1.1不启用 keepalive 是无效的 - location 中必须有
proxy_http_version 1.1;和proxy_set_header Connection "";——后者关键:清空后端可能返回的Connection: close,否则 Nginx 主动关掉复用连接 - 检查后端服务自身是否支持长连接:例如 Spring Boot 需设
server.tomcat.connection-timeout=-1或大于 Nginx 的proxy_read_timeout,否则后端先断,Nginx 还在等,fd 就卡住了
留意协议升级和特殊头部干扰
WebSocket、gRPC 或某些 API 客户端会主动发 Connection: Upgrade 或自定义 header,容易触发 Nginx 默认行为关闭复用:
- WebSocket 场景下,务必配全:
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade";,否则握手成功后连接仍可能被静默回收 - 避免在 proxy_set_header 中手动写
Connection: keep-alive,Nginx 会自动处理,冗余设置反而可能覆盖 upgrade 逻辑 - 检查是否有第三方模块(如某些 WAF 插件)或 rewrite 规则意外修改了 Connection 或 Upgrade 头


















