确认是文件描述符耗尽,需分层排查:若仅部分worker报错,可能是fd泄漏;若全部同步报错且dmesg提示file-max告警,则为内核级总量不足;应立即检查/proc/sys/fs/file-nr、各进程limits及lsof分布,并同步调高sysctl、limits.conf、systemd limitnofile和nginx worker_rlimit_nofile。

看到 Nginx 错误日志里反复出现 “accept() failed (24: Too many open files)”,基本可以确认是文件描述符(file descriptor,fd)耗尽了。但要注意:这个报错本身只说明 Nginx worker 拿不到新 fd,真正的问题可能在进程级、用户级,也可能是系统级——不能一看到这行日志就直接去改 worker_rlimit_nofile。
先区分是进程限制还是系统限制
关键看错误是否伴随其他线索:
- 如果
error.log中只有accept() failed (24: Too many open files),且集中在某几个 worker 进程(比如 PID 1234、5678),而其他 worker 正常,大概率是 该 worker 自身 fd 泄漏 或配置不当(如连接池未释放、长连接堆积) - 如果所有 worker 都频繁报这个错,且时间上高度同步,再结合
dmesg出现VFS: file-max limit reached或file descriptor limit reached,说明是 内核级 fd 总量告急 - 如果
nginx -t通过、服务能启动,但刚运行几分钟就崩,systemctl status nginx显示 “killed”,要立刻查dmesg | grep -i "file.*max\|descriptor"确认是否被内核拦截
快速验证当前 fd 使用状态
别猜,直接看数字:
- 运行
cat /proc/sys/fs/file-nr:输出三列,重点关注第一列(已分配 fd 总数)和第三列(file-max 上限)。若第一列 ≥ 第三列 × 0.9,风险极高 - 运行
cat /proc/sys/fs/file-max看上限值。高并发服务器建议设为 100 万以上,不是默认的 8192 或几万 - 对 Nginx 主进程 PID(非 worker),执行
ls -l /proc/<pid>/fd/ 2>/dev/null | wc -l</pid>查它当前打开的 fd 数。正常应几百到一两千;若持续过万,有泄漏嫌疑
定位高消耗进程和 fd 类型
系统级告警下,往往是个别进程“吃光”了资源:
- 用
lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr | head -10找出 fd 占用 Top 10 的 PID - 对可疑 PID,执行
lsof -p <pid> | awk '{print $5}' | sort | uniq -c | sort -nr</pid>看它主要在开什么:大量IPv4/IPv6表示连接没及时关闭;大量anon_inode可能是 eventfd/timerfd 泄漏;大量pipe或inotify则指向模块或脚本逻辑问题 - 特别注意:Nginx 的
worker_connections和worker_rlimit_nofile必须匹配。例如设了worker_connections 10240,但worker_rlimit_nofile还是默认 1024,必然触发报错
临时缓解与配置修正
线上先稳住,再根治:
- 临时提高内核上限:
sudo sysctl -w fs.file-max=1000000(立即生效,重启失效) - 永久生效:写入
/etc/sysctl.conf,加一行fs.file-max = 1000000,然后sysctl -p - Nginx 配置中,在
main块设置worker_rlimit_nofile 100000;,并在events块确保worker_connections≤ 该值的 70% 左右(留余量) - 检查
/etc/security/limits.conf,确认 Nginx 运行用户(如www-data)的nofile软硬限制已调高,否则worker_rlimit_nofile无法突破用户级限制











