ulimit -n仅影响当前shell会话,服务不生效因未配置limits.conf、systemd的limitnofile及内核fs.file-max三处;需pam加载、用户重新登录、服务重载并验证/proc//limits。

改完 ulimit -n 还是报 “Too many open files”,基本是因为只调了当前 shell,没动真正起作用的那几层限制。
为什么 ulimit -n 改了又变回 1024
这个命令只影响当前 shell 会话及其直接启动的子进程。关掉终端、su - user、或者用 sudo -u user cmd 启动服务,都不会继承这个值——PAM 没触发,limits.conf 没加载,systemd 更是完全无视它。
- 执行
ulimit -n 65536后,新开一个 tab 或重新 ssh 登录,ulimit -n又显示 1024 - 在 root 下设好,再
su - appuser,ulimit -n仍是 1024:因为su -不一定走完整 PAM session 流程 - 写进
/etc/profile或~/.bashrc也没用:systemd 服务不读这些文件,Java/Nginx 进程压根不是从 bash 启动的
永久生效必须配 /etc/security/limits.conf 并确认 PAM 加载
这是用户级限制的唯一可靠路径,但必须满足三个硬条件,缺一不可:
-
/etc/security/limits.conf里要分开写软硬限制,比如:appuser soft nofile 65536appuser hard nofile 65536
(别用appuser - nofile 65536,某些旧系统不认) -
/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/system-auth(RHEL/CentOS)中必须有这一行:session required pam_limits.so - 目标用户必须重新登录(不是
su,是完整 SSH 重连或 console 重新认证)
验证方式:先 su - appuser,再执行 ulimit -n —— 这时看到的才是 limits.conf 生效后的软限制。
systemd 服务必须单独加 LimitNOFILE
哪怕 limits.conf 写对了、用户也重新登录了,systemctl start nginx 启动的服务依然只有 1024 个 fd。因为 systemd 自己管理 cgroup 和资源限制,完全绕过 PAM。
- 编辑服务 unit 文件:
sudo systemctl edit nginx.service - 填入:
[Service]<br>LimitNOFILE=65536
- 重载并重启:
sudo systemctl daemon-reload && sudo systemctl restart nginx - 确认是否生效:
systemctl show nginx --property LimitNOFILE,输出应为LimitNOFILE=65536
注意:不要依赖 DefaultLimitNOFILE 设全局默认值,部分旧版 systemd 不支持,且容易被 service 文件里的显式设置覆盖。
别漏掉内核级总上限 fs.file-max
这个值控制整个系统能分配的文件描述符总数,所有进程加起来不能超它。默认值通常偏低(比如 180965),高并发场景下可能成为瓶颈。
- 查当前值:
cat /proc/sys/fs/file-max - 临时调高:
sudo sysctl -w fs.file-max=1048576 - 永久生效:往
/etc/sysctl.conf里加一行:fs.file-max = 1048576,再执行sudo sysctl -p
这个参数不直接影响单个进程,但若它太小,即使每个进程都设了 65536,系统也会在总量耗尽时报错。实际排查时,先看进程 fd 数(ls /proc/<pid>/fd | wc -l</pid>),再看系统总量,顺序不能反。











