nginx大文件下载导致fd瞬时耗尽,根源是缓冲机制与系统fd分配叠加;需同步调高系统、用户、服务三级file-max限制,并对下载location关闭proxy_buffering或缩小proxy_max_temp_file_size以减少临时文件fd占用。

遇到 Nginx 代理大文件下载时文件描述符(fd)瞬间耗尽,典型表现是 error.log 突然密集出现 accept() failed (24: Too many open files),且往往在用户发起多个大文件并发下载后几秒内爆发。这不是缓慢增长的泄漏,而是“脉冲式打满”,根源在于 Nginx 缓冲机制与系统 fd 分配策略的叠加效应。
重点看是否所有 worker 同步报错
如果全部 worker 进程(比如 PID 1001、1002、1003)在同一秒内都打出 accept() failed,且 dmesg | grep "file-max" 显示 VFS: file-max limit reached,说明不是某个 worker 泄漏,而是系统级 fd 总量被瞬时打穿。大文件下载会为每个分块请求(Range 请求)建立独立连接+临时文件句柄+缓冲区文件句柄,峰值 fd 消耗远超连接数本身。
查清 Nginx 实际打开的 fd 类型和数量
别只看 ulimit 或 file-nr 总数,要定位到 Nginx 主进程和 worker 的真实开销:
- 对 Nginx 主进程 PID:运行 ls -l /proc/
/fd/ 2>/dev/null | wc -l —— 正常几百;若超 3000,说明主进程自身(如日志轮转、共享内存)已吃紧 - 对任一高负载 worker PID:运行 lsof -p
| awk '$5 ~ /IPv4|IPv6/ {c++} END{print c}' 统计网络连接数;再运行 lsof -p| awk '$5 ~ /REG.*tmp/ {c++} END{print c}' 查临时文件句柄(proxy_temp_path 下的 .temp 文件)—— 若后者占总量 70% 以上,就是 proxy_buffering + proxy_max_temp_file_size 触发了大量磁盘缓冲文件
关键配置项必须协同调高
仅改 worker_rlimit_nofile 不够,必须三处同步放开:
- 系统级:修改 /etc/sysctl.conf,设 fs.file-max = 2000000,并执行 sysctl -p
- 用户级:在 /etc/security/limits.conf 中为运行 Nginx 的用户(如 www-data)加两行:www-data soft nofile 100000 和 www-data hard nofile 200000
- 服务级:用 systemctl edit nginx.service 添加 LimitNOFILE=100000,避免 systemd 覆盖 limits.conf
针对大文件下载做缓冲瘦身
默认 proxy_buffering on + proxy_max_temp_file_size 1024m 会让每个大文件下载生成多个 1GB 临时文件,每个文件至少占用 2–3 个 fd(open + read + write)。更稳妥的做法是:
- 对纯下载 location,显式关闭缓冲:proxy_buffering off;(避免写临时文件)
- 或保留缓冲但大幅缩小粒度:proxy_buffers 8 128k; + proxy_max_temp_file_size 128m;(减少单个 temp 文件体积,降低 fd 单次申请量)
- 确保 proxy_temp_path 所在分区有足够 inodes(df -i),inode 耗尽也会表现为 “Too many open files”











