热升级时易触发“Too many open files”因新旧worker并行导致fd总数翻倍,须同步调优内核fs.file-max、systemd LimitNOFILE、用户limits.conf及nginx worker_rlimit_nofile四层限制。

热升级(Upgrade)过程中,Nginx 的新老 worker 进程并不会“交接”文件描述符(fd)。这不是一个传递或迁移过程,而是一个并行共存、各自独立管理 fd 池的阶段——这正是 fd 溢出风险集中爆发的关键窗口。
为什么热升级时容易触发“Too many open files”
热升级(nginx -s upgrade)会启动一批新 worker 进程,同时旧 worker 仍持续处理存量连接。此时系统中活跃 worker 数量翻倍,每个 worker 都按 worker_rlimit_nofile 和 worker_connections 向系统申请 fd 配额。若配置未预留余量,极易突破以下任一限制:
- 单个进程的 soft/hard nofile 限制(来自 limits.conf 或 systemd LimitNOFILE)
- Nginx 主进程继承的 ulimit 值(影响所有子 worker 启动上下文)
- 内核全局上限 /proc/sys/fs/file-max,尤其当旧 worker 尚未退出、新 worker 已满载时,allocated fd 总数可能瞬间冲顶
如何验证升级期间的真实 fd 压力
别等报错再查,应在执行 nginx -s upgrade 后立即观察:
- 查新旧 worker PID:pgrep -f "nginx: worker",区分新旧(看启动时间:ps -o pid,lstart,comm -C nginx)
- 分别统计 fd 占用:lsof -p [PID] | wc -l,对比各 worker 实际使用量与 /proc/[PID]/limits 中 Max open files 的差值
- 看系统总池子是否告急:cat /proc/sys/fs/file-nr,三列数字中第二列(allocated)逼近第一列(file-max)即亮红灯
- 检查 dmesg 是否有内核拦截记录:dmesg | grep -i "file.*max\|descriptor"
必须同步调优的四个层级(缺一不可)
仅改 nginx.conf 中的 worker_rlimit_nofile 是无效的。必须确保四层限制形成向上收敛的链条:
- 内核级:设 fs.file-max ≥ (worker_processes × 2 + 10%) × worker_rlimit_nofile(多留 10% 给主进程、日志、临时文件等)
- systemd 级:在 /etc/systemd/system/nginx.service.d/override.conf 中写死 LimitNOFILE=65535,然后 systemctl daemon-reload && systemctl restart nginx
- 用户级:确认 nginx 启动用户(如 www-data 或 nginx)在 /etc/security/limits.conf 中有对应 hard/soft nofile 行,且未被 pam_limits.so 忽略
- Nginx 级:main 块设 worker_rlimit_nofile 65535;,events 块中 worker_connections 不超过该值的 90%
避免升级后残留导致的隐性泄漏
旧 worker 进入 shutdown 状态后,若因长连接(如 WebSocket、SSE、大文件下载)迟迟不退出,其 fd 不会释放,但新 worker 又在持续建连——这就形成双倍 fd 占用。应主动控制生命周期:
- 在 upstream 中启用 keepalive,并设置合理超时:keepalive_timeout 60s;,避免后端连接无限滞留
- 对客户端连接设硬性限制:keepalive_requests 1000;、keepalive_timeout 75s;
- 禁用无意义的缓存延长 fd 寿命:open_file_cache inactive=30s;、ssl_session_cache timeout=10m;
- 监控 stub_status 中 Active connections 数与 lsof 结果是否匹配,偏差过大即提示连接未正常关闭
热升级不是原子操作,而是资源压力测试。它暴露的是配置链路上最薄弱的一环。调优不是堆高数字,而是让每一层都清楚自己能分多少、该留多少余量、何时该退。


















