su - oracle报错su: cannot set user id: Resource temporarily unavailable

今天上线服务器连接数较多,我们知道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要设置得更大

点赞