Too many open files与limits.conf不生效
约 718 字大约 2 分钟
2026-08-29
Nginx、MySQL、Java 等服务的日志里出现 Too many open files,本质是进程打开的文件句柄数超过系统限制——Linux 默认单进程上限只有 1024,并发连接一多、日志一多就会打满。本文覆盖调大限制的完整流程,以及最常见的坑:"改了 limits.conf 却不生效"。
先确认当前限制
查看当前会话的句柄限制:
ulimit -n查看服务进程的实际限制(
<pid>换成进程号):cat /proc/<pid>/limits | grep "open files"看哪些进程占的句柄最多:
sudo lsof -n | awk '{print $1}' | sort | uniq -c | sort -rn | head
句柄打满的常见原因
- 并发连接数高(Nginx、数据库、爬虫)
- 大量日志文件长期打开、未轮转
- 程序 bug:文件/连接打开后不关闭(句柄泄漏),只能改代码或重启服务
临时调大(当前会话有效)
ulimit -n 65535只对当前 shell 及其之后启动的进程生效,重新登录即失效,适合临时验证。
永久调大:limits.conf
编辑 /etc/security/limits.conf(或新建 /etc/security/limits.d/99-nofile.conf),追加:
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535退出重新登录后生效,ulimit -n 应显示 65535。soft 是当前生效值,hard 是 soft 能调到的上限。
别一次拉太高
单个进程的 hard 限制不能超过系统参数 fs.nr_open(默认 1048576),需要更大值时先改它。整机句柄总上限由 fs.file-max 控制,一般无需调整。
改了 limits.conf 还是不生效?
按命中率排查:
systemd 服务不读 limits.conf(最常见)
limits.conf 由 PAM 在用户登录时应用;Nginx、MySQL、Docker 这类由 systemd 拉起的服务不走 PAM,所以怎么改都没用。要给服务单独设置:
sudo systemctl edit nginx写入:
[Service]
LimitNOFILE=65535保存后重载并验证:
sudo systemctl daemon-reload
sudo systemctl restart nginx
cat /proc/$(pidof nginx | head -1)/limits | grep "open files"MySQL、Redis、Java 服务同理,把 nginx 换成对应服务名。
会话没有重新登录
limits.conf 只在登录那一刻读取,改动之前打开的会话仍是旧值。退出重连,或 su - 用户 切换后再验证。
确认没有旧配置覆盖
/etc/security/limits.d/ 下的文件会覆盖 limits.conf 的同名项,检查有没有历史遗留配置:
grep -r nofile /etc/security/limits.conf /etc/security/limits.d/ 2>/dev/null持续增长就是句柄泄漏
隔几分钟重复统计一次,某进程句柄数持续增长不回落,多半是程序没释放资源:
ls /proc/<pid>/fd | wc -l # 精确统计某进程当前句柄数短期缓解:重启对应服务;根治要修代码。系统整体水位用 cat /proc/sys/fs/file-nr 查看。
进程与资源的更多排查手段参见Linux资源查看基础命令。
