ulimit 与 systemd 的 LimitNOFILE 联动
发布时间:2026-04-25 12:43       
更新时间:2026-04-26 07:49
问题很典型:明明改了 /etc/security/limits.conf,把 nofile 调到 65535,服务重启后报错 Too many open files 依旧,cat /proc/进程PID/limits 里还是 1024。原因是:limits.conf 只对 PAM 登录会话生效,而现在的大多数服务由 systemd 拉起,systemd 不走 PAM,自然不读这个文件。
## 为什么两条路各管各的
SSH 登录后手工启动的进程经过 PAM 认证,pam_limits 模块读取 limits.conf,所以手工跑没事;systemd 管理的服务有自己的资源控制体系,每个 unit 的上限由 unit 文件或全局配置决定,默认值往往就是 1024。同一个程序,换一种启动方式,上限就变了。还有一个易漏点:limits.conf 同目录下的 limits.d/ 会追加读取,同名条目以后读到的为准,排查时两个文件都要看。确认进程属于哪套体系有个窍门:看父进程,父进程是 systemd(PID 为 1)的就是服务,挂在 sshd 下的就是登录会话。
## 服务单元里加字段
针对单个服务,在 unit 文件的 [Service] 段加一行:
```
sudo systemctl edit nginx
# 编辑器里写入:
[Service]
LimitNOFILE=65535
```
systemctl edit 生成覆盖配置,不直接改原始文件,软件升级不受影响。保存后执行 systemctl daemon-reload && systemctl restart nginx,再用 cat /proc/$(pidof nginx)/limits 验证,Max open files 一行应显示新值。Nginx 这类多进程架构的服务,worker 会继承 master 的上限,改一处全体生效。有些应用自己还会再设一层限制,内核侧改完仍报错时,去翻应用的配置文件。
## 全局兜底与在线调整
多台机器、多个服务都要放宽时,改全局默认:在 /etc/systemd/system.conf 与 user.conf 里设 DefaultLimitNOFILE=65535,重启后对所有服务生效。来不及重启服务也可以在线调整单个进程的上限:prlimit --pid 进程号 --nofile=65535,应急有用,但重启后失效,还是要落到 unit 配置里,prlimit 属于 util-linux 包,主流发行版默认自带。
排查动作照此顺序:先看 /proc/PID/limits 确认当前值;值没变,就确认服务确实由 systemd 管理(systemctl status 里有主 PID);再查覆盖配置是否落位,systemctl show 服务名 -p LimitNOFILE 一查便知。两套体系记住一句话:PAM 管登录会话,systemd 管服务,改错了地方,改得再大也不生效。动手前把两处的当前值都记录下来,改完对比,避免来回猜。