今天上线服务器连接数较多,我们知道ORACLE是多进程数据库,那么一个session
往往对应了一个OS的process,今天使用root进行切换的时候居然报错。
在测试上模拟再现
[root@testmy proc]# su – oracle
su: cannot set user id: Resource temporarily unavailable
出现这个这个错误当然第一反应是查看ulimit -a,如果真是资源不够了卧槽就悲剧
了
我使用开始连接好的进行查看:
[oracle@testmy ~]$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 31501
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 16384
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
一般我们需要关注
max user processes (-u) 16384
open files (-n) 65535
用户可以打开的最大进程数和每个进程可以打开的最大文件数量,当然这个限制是hard限制。
不管怎么样明显没有超出,因为我的进程总数才1000多个,而且数据库日志没有任何报错,如
果资源不够那么就会出现比如fork进程失败的报错,或者超过最大文件数的报错,但是这里
没有,松了一口气。那么为什么出现这样的情况。查了一会资料发现没什么鸟用,那么我只
有自己找原因了。
首先明确问题:
1、ORACLE用户进程的总数没有超过hard限制,ORACLE没有任何问题
2、su – oracle报资源错误
Resource temporarily unavailable
那么我们只能从su – oracle做了什么入手了,首先要明确su – oracle到底做了什么实际上就是
bash(23799)───su(23819)───bash(23820)
bash fork 一个进程进行 su命名执行然后 su fork 一个进程出来 跑bash进程。好那么我们进行
strace:
strace -o strace.log -f -ff su – oracle
-f表示trace fork出来的子进程 -ff表示在strace.log后面加上进程的pid
出来如下:
-rw-r–r– 1 root root 3330 Jan 4 08:52 strace.log.4804
-rw-r–r– 1 root root 40230 Jan 4 08:52 strace.log.4803
首先看一下strace.log.4804
找到重点:
setgroups(2, [501, 502]) = 0
setgid(501) = 0
setuid(502) = -1 EAGAIN (Resource temporarily unavailable)
setuid(502)的时候返回-1 报错并且设置errno为EAGAIN并且报错了Resource temporarily unavailable
(
#define EWOULDBLOCK EAGAIN /* Operation would block */)
setuid系统调用就是用于改变其有效userid的,那么我们看看setuid的返回值
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
ERRORS
EAGAIN The uid does not match the current uid and uid brings process over its RLIMIT_NPROC resource limit.
EPERM The user is not privileged (Linux: does not have the CAP_SETUID capability) and uid does not match the real UID or saved set-user-ID of
the calling process.
显然这里我们可能的原因就是over its RLIMIT_NPROC resource limit,RLIMIT_NPROC位用户允许的最大进程数,
RLIMIT_NPROC
The maximum number of processes (or, more precisely on Linux, threads) that can be created for the real user ID of the calling process.
Upon encountering this limit, fork(2) fails with the error EAGAIN.
那么ORACLE允许的进程数hard限制为16384明显没有超出,那么只可能是超过了其soft限制看看另外一个文件找到关键
setrlimit(RLIMIT_NPROC, {rlim_cur=1024, rlim_max=16*1024}) = 0
这里的rlim_cur为soft限制,为1024个,结构体如下:
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
卧槽原因找到了,然后就要找到为什么是1024查看/etc/security/limits.conf
设置为:
* soft nproc 16384
* hard nproc 16384
* soft nofile 65535
* hard nofile 65535
也不是1024啊,然后查看/etc/security/limits.d/90-nproc.conf
* soft nproc 1024
root soft nproc unlimited
这里出现了1024,应该就是使用的这里的1024,然后修改后
* soft nproc 16384
切换成功再次查看
setrlimit(RLIMIT_NPROC, {rlim_cur=16*1024, rlim_max=16*1024}) = 0
看到这里rlim_cur设置为了16*1024也就是16384.看来su 的时候确实是使用
的nproc的soft限制,那么这里涉及2个文件
/etc/security/limits.d/90-nproc.conf
/etc/security/limits.conf
我们在上面的案例中看到当设置为
* soft nproc 1024这种的时候
90-nproc.conf 的优先级大于limits.conf,
但是经过我测试如果limits.conf 中如果指定用户
如:
oracle soft nproc 16384
会高于90-nproc.conf 。
同时要注意一下
90-nproc.conf这个文件生效的范围:
The issue starts only after upgrading the kernel later to 2.6.32-431.el6.x86_64
最后总结一下:
1、su -的时候使用的是soft限制
2、为了保证没有问题请这样设置
/etc/security/limits.conf
* soft nproc 16384
* hard nproc 16384
* soft nofile 65535
* hard nofile 65535
同时设置/etc/security/limits.d/90-nproc.conf
为
* soft nproc 16384
设置profile也是:
if [ $USER = “oracle” ] || [ $USER = “grid” ]; then
if [ $SHELL = “/bin/ksh” ]; then
ulimit -u 16384
ulimit -n 65535
else
ulimit -u 16384 -n 65535
fi
umask 022
fi
当然这里的设置为你实际的大小比如你的数据库最大会话数都超过了16384当然
nproc要设置得更大