需从系统级、用户级、进程级协同优化文件描述符限制:查真实值用/proc/*/limits,调file-max用sysctl,设limits.conf配pam,systemd服务须用limitnofile,注意子进程继承与容器配置。

要防止 Linux 系统因文件描述符(fd)耗尽而出现“Too many open files”错误,不能只调大某一层限制,必须从系统级、用户级、进程级三方面协同优化。关键不是盲目设高,而是让各层限制合理匹配,并确保配置真正生效。
查清当前实际限制值
很多问题源于误判真实生效值。不要只信 ulimit -n,它只反映当前 shell 的软限制:
- 查系统总上限:
cat /proc/sys/fs/file-max - 查指定进程真实限制:
cat /proc/<pid>/limits | grep "Max open files"</pid>(最权威) - 查当前会话软硬限制:
ulimit -Sn和ulimit -Hn - 查已用 fd 总量:
cat /proc/sys/fs/file-nr(输出三项:已分配、未使用、上限)
调高系统级全局上限(file-max)
这是整个内核能分配的 fd 总数,所有进程加起来不能超过它。设太小会直接卡死,设太大则浪费内存(每个 fd 占约 1KB 内核内存):
- 临时调整(重启失效):
sudo sysctl -w fs.file-max=2097152 - 永久生效:在
/etc/sysctl.conf中追加fs.file-max = 2097152,再运行sudo sysctl -p - 推荐估算值:按物理内存(MB)× 10,或按峰值并发连接数 × 1.5~2。例如 64GB 内存服务器可设为 655360~1310720
配置用户级默认限制(limits.conf)
该配置通过 PAM 在用户登录时加载,影响所有以该用户身份启动的普通进程(如手动启的 nginx、python 脚本):
- 编辑
/etc/security/limits.conf,添加两行(以 www-data 为例):www-data soft nofile 65535www-data hard nofile 65535 - 若需对所有用户生效,用通配符:
* soft nofile 65535和* hard nofile 65535 - 确认 PAM 模块已启用:
grep pam_limits.so /etc/pam.d/common-session,缺失则追加session required pam_limits.so - 修改后必须重新登录(或重启对应服务),否则不生效
单独处理 systemd 服务(LimitNOFILE)
nginx、redis、mysql 等由 systemd 管理的服务**完全不读取 limits.conf**。必须显式配置 unit 文件:
- 方式一(推荐,用 drop-in):
sudo systemctl edit nginx.service,输入:[Service]LimitNOFILE=65535 - 方式二(全局默认):编辑
/etc/systemd/system.conf,取消注释并修改DefaultLimitNOFILE=65535 - 修改后务必执行:
sudo systemctl daemon-reload && sudo systemctl restart nginx.service - 验证:
systemctl show -p LimitNOFILE nginx.service或查其进程的/proc/<pid>/limits</pid>
额外注意点
有些场景容易忽略:
- Go/Python 等语言启动子进程时,默认继承父进程的 fd 限制;若主进程没提前调大,子进程仍卡在 1024
- 某些容器环境(如 Docker)需在 run 命令中加
--ulimit nofile=65535:65535或配置 daemon.json - 如果应用使用 inotify 监控大量文件,还需调大
fs.inotify.max_user_watches - 避免把
fs.file-max设到几千万——可能引发 slab 内存压力,且掩盖 fd 泄漏问题











