单靠 ulimit -n 无法解决“too many open files”,必须同步配置 fs.file-max(系统总池)和 nofile(进程上限)。ulimit -n 仅作用于当前 shell 子进程,受硬限制约束,且不影响 systemd 服务和容器;永久生效需配 limits.conf + pam、sysctl.conf 和 systemd limitnofile。

直接说结论:单靠 ulimit -n 改不了系统级最大句柄数,它只管单个进程;真正要防“打开文件过多”,必须同时调 fs.file-max(系统总池)和 nofile(进程上限),缺一不可。
为什么 ulimit -n 设置了还是报 “Too many open files”
常见现象是执行 ulimit -n 65535 后,程序启动仍卡在 1024。根本原因有三个:
-
ulimit -n只影响当前 shell 及其子进程,新开的终端或 systemd 服务完全不认它 - 软限制(soft limit)不能超过硬限制(hard limit),而硬限制默认常为 4096,
ulimit -n 65535实际被静默截断 - 即使进程上限提上去了,如果
/proc/sys/fs/file-max太小(比如默认 32768),多个进程一起开句柄,系统全局池先耗尽,照样报错
永久修改用户级进程句柄上限(nofile)
这是最常漏掉也最容易出错的一环。关键不是写对数字,而是让 PAM 真正加载它:
- 编辑
/etc/security/limits.conf,添加两行(注意空格不能用 Tab,必须是空格):* soft nofile 65535* hard nofile 65535 - 确认
/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/system-auth(RHEL/CentOS)里有未注释的这行:session required pam_limits.so - 改完必须全新登录(SSH 重连、GUI 登出再进),不是新开个 terminal 标签页
- 验证方式:登录后立刻跑
ulimit -n和ulimit -Hn,两个值都得是 65535
永久修改系统级总句柄池(fs.file-max)
这个值决定整个系统能分配多少文件描述符,不是“建议值”,是硬性天花板:
- 查看当前值:
cat /proc/sys/fs/file-max - 临时生效(重启失效):
sudo sysctl -w fs.file-max=1048576 - 永久生效:往
/etc/sysctl.conf追加一行:fs.file-max = 1048576,然后运行sudo sysctl -p - 别设太高——超过 200 万可能引发内核内存压力;一般 100 万足够支撑千并发 HTTP 服务
- 顺手检查下当前使用量:
cat /proc/sys/fs/file-nr,输出三列,第三列是file-max,第二列是已用数
systemd 服务必须单独配 LimitNOFILE
nginx、redis、node.js 这类用 systemctl start 启的服务,完全无视 limits.conf。它们走的是 systemd 的资源控制路径:
- 全局生效(影响所有新启 service):
编辑/etc/systemd/system.conf,取消注释并设:DefaultLimitNOFILE=65535 - 单服务生效(推荐,更可控):
编辑/etc/systemd/system/your-service.service,在[Service]段加:LimitNOFILE=65535 - 改完必须执行:
sudo systemctl daemon-reload && sudo systemctl restart your-service - 验证是否生效:
systemctl show your-service | grep LimitNOFILE
最容易被忽略的点:容器环境(Docker/containerd)有自己的 ulimit 层级,宿主机改了 limits.conf 或 sysctl,容器里默认仍是 1024。要用 --ulimit nofile=65535:65535 或 ulimits 字段显式透传,否则白调。











