Nginx事件驱动模型依赖文件描述符(FD)限制,epoll本身无硬限但受制于系统ulimit、内核file-max、systemd LimitNOFILE及worker_rlimit_nofile四层限制;worker_connections须≤0.7×worker_rlimit_nofile,并配合open_file_cache、access_log buffer、keepalive优化减少FD消耗。

Nginx 的事件驱动模型本身不直接“处理”文件描述符限制,而是高度依赖并受制于 FD 限制——它决定了模型能实际调度多少并发连接。关键不是模型多先进,而是它能否拿到足够 FD 资源来运行。
epoll 是载体,FD 数量才是天花板
Linux 下 Nginx 默认使用 epoll,它支持数十万级并发,但前提是每个连接对应的 socket、静态文件句柄、日志 buffer、upstream 连接等都能成功分配 FD。若系统只给每个 worker 进程 1024 个 FD,那即使 epoll 再高效,最多也就维持约 800–900 个活跃连接(还要预留日志、缓存等开销)。
- select 模型有硬编码限制(FD_SETSIZE,默认 1024),epoll 没有,但受制于进程级 ulimit 和内核总上限
- worker_connections 值只是逻辑上限,真正起作用的是 worker_rlimit_nofile × 实际可用率(建议 ≤ 0.7)
- 一个 HTTP 请求可能消耗多个 FD:客户端 socket + 后端 proxy socket + 静态文件 open() + access_log buffer(若未启用 buffer/flush)
四层限制必须全部打通,epoll 才能跑满
epoll 的能力只有在整条 FD 供给链路畅通时才能释放。任一层卡住,都会让 epoll_wait 返回 EMFILE 或导致 accept() 失败:
- 内核全局:/proc/sys/fs/file-max 必须 ≥ 所有 worker 进程的 FD 需求总和 × 2(防突发)
- 用户级:/etc/security/limits.conf 中 nginx 用户的 hard nofile 必须 ≥ worker_rlimit_nofile
- systemd 级:LimitNOFILE 必须显式设置,否则 systemd 会覆盖 limits.conf(尤其 Ubuntu/Debian 22.04+)
- Nginx 配置级:worker_rlimit_nofile 必须设值,且不能高于 hard nofile;worker_connections 必须 ≤ 0.7 × worker_rlimit_nofile
优化不是堆数字,而是减少 FD 消耗频次
epoll 效率高在事件就绪通知,但频繁 open/close 小文件仍会快速耗尽 FD。这时需配合缓存机制降低实际打开次数:
- 启用 open_file_cache:缓存文件元数据与句柄,避免每次请求都 open/close
- access_log 加 buffer=64k flush=5s:把日志写入从每次请求一次,变成批量刷盘,显著减少 write() 相关 FD 占用
- keepalive_timeout 和 keepalive_requests 合理设置:复用 TCP 连接,避免短连接反复创建 socket FD
- 禁用不必要的模块(如未用的 upstream 或 log_format):减少隐式 FD 分配路径
验证是否真由 epoll 或 FD 引起?看错误码
别猜。当出现连接拒绝或 502/504,立刻查:
- error.log 是否含 accept() failed (24: Too many open files) → 明确是 FD 耗尽
- cat /proc/$(pgrep -f "nginx: worker" | head -n1)/limits | grep "Max open files" → 看 Soft Limit 是否达标
- lsof -p $(pgrep -f "nginx: worker" | head -n1) | wc -l → 对比当前打开数与 Soft Limit 差距
- 若差距小但仍有失败,再查是否后端超时导致 upstream socket 积压未关闭(FD 泄漏)



















