su - oracle報錯su: cannot set user id: Resource temporarily unavailable

gaopengtttt發表於2017-01-04
今天上線伺服器連線數較多,我們知道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要設定得更大

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2131894/,如需轉載,請註明出處,否則將追究法律責任。

相關文章