服务器文件句柄耗尽too many open
服务器出现 too many open files 报错,本质是打开的文件句柄数量到达上限。
句柄可以粗略理解为 Linux 里对文件和网络连接的引用编号,每个连接、每个日志文件都要占一个。
本文帮你从系统和进程两个层面查清限制值,并给出临时与永久修改方法,最后验证修改是否真正生效。
先确认是系统限制还是进程限制
登录服务器分别执行下面两条命令:
# 查看整个系统当前允许的最大文件句柄数
cat /proc/sys/fs/file-max
# 查看当前 shell 的软限制和硬限制
ulimit -n
ulimit -n 输出的是当前终端能打开的文件句柄数,默认通常为 1024 或 65535。
如果 Nginx、MySQL、Java 等服务启动时显示 too many open files,还要确认具体进程的限制:
# 找到服务进程 PID
ps aux | grep nginx
# 查看进程实际限制
cat /proc/PID/limits
重点看 Max open files 一行的软限制和硬限制。
软限制可以临时调高,硬限制是最终天花板,修改时不能超过它。
临时修改与永久配置 ulimit
先做临时修改,方便快速验证:
# 软限制和硬限制都改成 65535
ulimit -n 65535
这种修改只对当前终端窗口生效。
要永久生效,编辑系统级配置文件:
echo -e "* soft nofile 65535\n* hard nofile 65535" >> /etc/security/limits.conf
注意 * 表示所有普通用户。
如果服务用 root 启动,建议同时加一行:
root soft nofile 65535
root hard nofile 65535
CentOS 或部分系统还需要在 /etc/profile 或 /etc/bashrc 中追加:
ulimit -n 65535
保存后退出重新登录,再执行 ulimit -n,确认输出变成 65535。
特别处理 systemd 和宝塔环境
如果你的服务由 systemd 管理,单独设置 limits.conf 不一定生效,因为 systemd 会忽略部分 PAM 限制。
需要编辑对应 service 文件:
systemctl edit nginx
写入:
[Service]
LimitNOFILE=65535
保存后重载并重启服务:
systemctl daemon-reload
systemctl restart nginx
宝塔面板用户可以在软件商店对应服务设置里调整“最大文件数”,或者手动修改 /etc/systemd/system/nginx.service 同路径配置。
千万不要只改 limits.conf 却跳过 systemd,否则重启后限制可能又被拉回默认值。
验证修改是否真正生效
修改完以后不要只看 ulimit -n,要分别确认这几项:
# 查看系统全局已分配句柄数
cat /proc/sys/fs/file-nr
# 查看 Nginx master 进程限制
cat /proc/$(cat /var/run/nginx.pid)/limits | grep "Max open files"
# 观察服务日志
grep "too many open files" /var/log/nginx/error.log
如果 file-nr 第三列已经接近 file-max,说明系统总量也偏小,可以临时提高系统上限:
sysctl -w fs.file-max=1200000
永久生效写在 /etc/sysctl.conf 中:
fs.file-max=1200000
然后执行 sysctl -p 加载。
常见避坑注意点
第一,硬限制必须大于等于软限制,否则修改会失败。
第二,重启服务后必须再查一遍 /proc/PID/limits,很多“改完又被杀掉”的场景都是因为忘改 systemd 配置。
第三,高并发服务不只吃文件句柄,修改后建议同时观察内存和连接数,避免盲目调大掩盖真实问题。
在生产环境操作前,先参考官方文档确认当前版本默认值,再小步修改并验证接口可用性。
完成以上步骤后,too many open files 基本可以消除。
后续如果还有类似报错,优先查看 dmesg 和对应应用日志,判断是否出现连接泄漏或文件未关闭的问题。