ulimit -n 修改仅作用于当前shell及其子进程,服务进程需通过pam或systemd单独配置limitnofile,且须验证/proc/pid/limits确认生效。

改完 ulimit -n 还是报 “Too many open files”,说明你只调了当前 shell 的软限制,而真正跑服务的进程压根没继承到——它要么没走 PAM 登录流程,要么是 systemd 管理的服务,默认无视 /etc/security/limits.conf。
为什么 ulimit -n 改了又变回 1024
因为 ulimit 命令只作用于当前 shell 及其直接子进程,退出终端、重启、或用 systemctl start 启动服务时完全不生效。常见错误包括:
- 在 root 下执行
ulimit -n 65536,再su - appuser,结果仍是 1024(su -不一定触发完整 PAM session) - 在
/etc/profile里加ulimit -n 65536,但systemctl start myapp启动后仍报错(systemd 不读 profile) - 改了
/etc/security/limits.conf却没确认pam_limits.so是否加载,也没重新登录
/etc/security/limits.conf 配置生效的三个硬条件
这个文件不是“保存就生效”,必须同时满足:
-
/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/system-auth(RHEL/CentOS)中存在session required pam_limits.so - 用户必须重新登录(SSH 重连、console 重新登录),仅
su - user或sudo -i不保证触发 PAM session 初始化 - 配置格式严格:软限和硬限必须分开写,且
soft ≤ hard;*不对 root 生效,需显式写root soft nofile 65536和root hard nofile 65536
推荐写法:
root soft nofile 65536 root hard nofile 65536 * soft nofile 65536 * hard nofile 65536
systemd 服务必须单独配 LimitNOFILE
从 systemd 219+ 开始,所有 systemctl start 启动的服务默认绕过 limits.conf,因为它们运行在独立 cgroup session 中。这时候即使 limits 写对了也白搭。
- 编辑服务单元:
sudo systemctl edit nginx.service - 填入:
[Service] LimitNOFILE=65536
- 重载并重启:
sudo systemctl daemon-reload && sudo systemctl restart nginx - 验证是否打到进程上:
cat /proc/$(pgrep nginx)/limits | grep "Max open files",输出应为65536 65536
别漏掉内核级总上限 fs.file-max
单个进程设再高,如果系统总句柄池不够,照样卡死。查当前值:cat /proc/sys/fs/file-max。
- 临时调高:
sudo sysctl -w fs.file-max=2097152 - 永久生效:在
/etc/sysctl.conf加fs.file-max = 2097152,再执行sudo sysctl -p - 注意:
fs.file-max是整个系统所有进程共用的上限,不是 per-process;它的值通常应 ≥ 所有关键服务LimitNOFILE之和 × 1.5
最常被忽略的是:改完所有配置后,没去 /proc/<code>PID/limits 看真实生效值——只信 ulimit -n 输出,等于没验证。











