根本原因是limits.conf依赖PAM的pam_limits.so模块,而su不带-、systemd服务等场景不经过PAM认证,导致配置未加载;需确保login shell登录或在systemd service中显式设置LimitNOFILE。
为什么改了 /etc/security/limits.conf 但 ulimit -n 没变?
根本原因:oracle 用户登录时没真正加载 limits.conf —— 大多数情况是用了 su - oracle 而不是直接登录,或 systemd 服务绕过了 pam 限制。
关键点:limits.conf 依赖 PAM 的 pam_limits.so 模块生效,而该模块只对通过 PAM 认证的会话起作用。systemd 启动的 Oracle 实例(比如用 systemctl start oracle-db)默认不走 PAM,su 不带 - 也不会读取 login shell 的 limits。
- 确认是否走 PAM:检查
/etc/pam.d/login或/etc/pam.d/sshd是否含session required pam_limits.so - Oracle 用户必须用 login shell 登录(
su - oracle或 SSH 直连),不能用su oracle - 如果用 systemd 管理 Oracle 服务,需在 service 文件里显式设置:
LimitNOFILE=65536
nofile 配置要写 soft 还是 hard?两者的区别在哪?
soft 是当前生效值,hard 是 soft 能设的上限;Oracle 进程启动时通常按 soft 值设 RLIMIT_NOFILE,但某些版本(如 19c+)会主动尝试提升到 hard 值 —— 所以两个都得配,且 hard ≥ soft。
常见错误是只写一行 oracle soft nofile 65536,结果 Oracle 启动时报 ORA-27123: unable to attach to shared memory segment,其实是 open file limit 不足导致共享内存分配失败。
- 必须成对配置:
oracle soft nofile 65536和oracle hard nofile 65536 - 不要用
*通配符代替用户名,Oracle 用户名是精确匹配的 - 数值别盲目拉高:Linux 内核有
/proc/sys/fs/nr_open上限,超了会静默截断(比如设 100000 但nr_open=1048576,实际生效可能只有 1024)
Oracle 12c/19c/21c 下验证 nofile 是否真生效
不能只信 ulimit -n,因为那是当前 shell 的值;Oracle 后台进程(如 ora_pmon_<SID>)可能继承的是不同上下文的 limits。
最可靠方式是查进程运行时的实际限制:
- 先找 Oracle 进程 PID:
ps -u oracle -o pid,comm | grep pmon - 再查它的 limits:
cat /proc/<PID>/limits | grep "Max open files" - 如果显示
65536 65536 files才算真正生效;若仍是1024 4096,说明 PAM 没加载或 systemd 覆盖了它
注意:Oracle RAC 环境中每个节点都要单独验证,不能只看一个。
systemd 环境下绕过 limits.conf 的正确姿势
现代 Oracle 安装(尤其 RPM 包或云上部署)越来越多用 systemd 启动监听器和数据库,这时 limits.conf 完全无效 —— 必须在 service 单元文件里硬编码。
路径通常是 /usr/lib/systemd/system/oracle-rdbms.service 或自定义的 /etc/systemd/system/oracle-db.service:
[Service] LimitNOFILE=65536 LimitNPROC=16384
改完后必须执行:systemctl daemon-reload && systemctl restart oracle-db,否则配置不加载。
- 不要试图在
EnvironmentFile里 exportulimit—— systemd 不认 shell 内建命令 -
LimitNOFILE是 per-process 限制,不是整个服务的总和;Oracle 多个后台进程各自独立受此值约束 - 如果同时用了
limits.conf和LimitNOFILE,后者优先级更高
真实场景里,一半以上的 ORA-27123 或监听器拒绝新连接问题,根子都在这里 —— 以为改了 conf 就万事大吉,其实进程压根没读它。










