systemd服务必须显式配置limitnofile,因默认忽略/etc/security/limits.conf;需通过systemctl edit修改服务单元文件,添加[service] limitnofile=65535,并重载重启验证。

直接改 /etc/security/limits.conf 并不能让所有进程生效,尤其是 systemd 启动的服务——这是最常踩的坑。
为什么 ulimit -n 看着改了,程序还是报 “Too many open files”?
因为进程启动方式不同,继承的限制来源也不同:
- 交互式 shell 会读
/etc/security/limits.conf(需 PAM 加载pam_limits.so) - systemd 服务默认**忽略** limits.conf,走自己的
LimitNOFILE配置 - docker 容器内进程受宿主机
sysctl fs.file-max和容器启动参数(--ulimit)双重约束 - 某些守护进程(如 nginx、redis)还会在自身配置里硬编码默认值,覆盖系统设置
所以只改 limits.conf,对 systemctl start 的服务完全无效。
systemd 服务必须显式设置 LimitNOFILE
以 nginx 为例,不能指望它自动读用户级 nofile 限制。得单独配 service unit:
sudo systemctl edit nginx.service
填入:
[Service] LimitNOFILE=65535
然后重载并重启:
sudo systemctl daemon-reload sudo systemctl restart nginx
验证是否生效:
cat /proc/$(pgrep nginx)/limits | grep "Max open files"
注意:LimitNOFILE 值不能超过该用户的 hard nofile 限制(即 limits.conf 里的 hard nofile),否则启动失败。
limits.conf 生效的两个硬性前提
很多人改完 limits.conf 就以为万事大吉,但以下两点缺一不可:
-
/etc/pam.d/common-session或对应登录类型文件(如sshd)中必须有这行:session required pam_limits.so - 修改后必须**重新登录用户会话**(不是只
source /etc/profile),或用su - $USER切换,否则 shell 不会重新加载 PAM 限制
常见误区:把配置写成 * soft nofile 65535 却忘了加 hard 行——软限制无法超过硬限制,结果实际生效的仍是默认 1024。
别漏掉系统级上限 fs.file-max
即使每个用户和进程都设到 65535,如果 fs.file-max 太小(比如默认只有 8192),整个系统撑不住高并发连接。
检查当前值:
cat /proc/sys/fs/file-max
临时提高:
sudo sysctl -w fs.file-max=1048576
永久生效,追加到 /etc/sysctl.conf:
echo "fs.file-max = 1048576" | sudo tee -a /etc/sysctl.conf sudo sysctl -p
这个值建议设为单个进程最大 nofile × 预估并发进程数的 1.5 倍以上,否则内核会拒绝分配新 fd,连 open() 系统调用都会直接返回 -EMFILE。
真正容易被忽略的是:systemd 服务的 LimitNOFILE 和用户登录会话的 limits.conf 是两套独立机制,必须分别处理;而 fs.file-max 是它们共同的天花板,调得再高,没配好前两者也白搭。











