调整 fs.file-max 能解决系统级文件句柄耗尽问题,但多数报错其实源于单进程限制,需同时检查 ulimit 设置。
先说结论:调整内核参数只是其中一环,务必区分系统总量限制与单进程限制。
- 先确认:区分是系统级 ENFILE 还是进程级 EMFILE 报错
- 先处理:同时修改 sysctl 配置与 limits 配置
- 再验证:观察 file-nr 变化并重启相关服务
命令速用版
临时生效(重启失效):
sysctl -w fs.file-max=2097152
永久生效:
echo "fs.file-max=2097152" >> /etc/sysctl.conf sysctl -p
为什么会这样
Linux 内核将打开的文件视为系统资源。file-max 代表整个系统能打开的文件句柄总数,而每个进程还有自己的限制(ulimit)。当系统总占用达到 file-max,或单个进程占用达到 ulimit 限制时,都会报“打开文件数过多”。
分步处理
1. 查看当前系统限制与使用情况:
cat /proc/sys/fs/file-max cat /proc/sys/fs/file-nr
file-nr 的三个数字分别代表已分配、已分配但未释放、最大限制。如果第一个数字接近第三个,说明系统级限制到了。
2. 修改内核参数:
编辑 /etc/sysctl.conf 或 /etc/sysctl.d/99-custom.conf,添加:
fs.file-max=2097152
执行 sysctl -p 使配置生效。
3. 修改单进程限制(关键):
编辑 /etc/security/limits.conf,添加:
* soft nofile 65535 * hard nofile 65535
注意:某些服务需要在 systemd 单元文件中单独配置 LimitNOFILE。
怎么验证是否生效
再次执行 cat /proc/sys/fs/file-nr,观察第一个数字是否不再卡在最大值附近。对于进程限制,在新登录的会话中执行 ulimit -n 查看。
常见坑
1. 只改 file-max 不改 ulimit:大部分应用报错是因为单进程限制,而非系统总量。
2. 修改后未重启服务:已运行的进程不会自动继承新的 ulimit 限制,需重启服务或重新登录。
3. 忽视文件泄漏:如果文件数持续上涨不回落,可能是程序未关闭文件句柄,调大限制只是延缓问题。
参考来源
- The Linux Kernel Documentation - fs.txt: https://www.kernel.org/doc/html/latest/admin-guide/sysctl/fs.html
- Linux man-pages - proc(5): https://man7.org/linux/man-pages/man5/proc.5.html
- Linux man-pages - sysctl(8): https://man7.org/linux/man-pages/man8/sysctl.8.html