记一次root用户su报错的处理过程

现象

  1. 直接使用foobar用户SSH登录正常
  2. 在root用户下,实行su - foobar,报错:
su: cannot set user id: Resource temporarily unavailable

只有su的时候报错,虽然不影响foobar用户正常的SSH远程登录,但这种资源受限的错误,一般都是系统崩溃的前兆,必须要较点真。

系统:RHEL 6.5

排查过程

先按套路出牌

首先直接一通free -mtopvmstat等等,试试运气
不过也不出所料,并没有什么收获。但这也算是个好消息,至少说明不像是系统级别的资源问题了。

感觉八成是线程数或者文件打开数搞的鬼了,懒得监控日志,接着排查。

查看线程数

cat /proc/sys/kernel/threads-max
254529

最大线程数254529,没有问题

ps -u foobar -L | wc -l
1045

用户当前线程数1045,虽然挺高了,但这个用户下部署的应用也非常多,算是正常吧。

检查ulimit

  1. 先用ulimit看一下设置的最大文件打开数
    用foobar直接登录,然后实行:
ulimit -n
655360

显示655360,没有问题

  1. 然后用lsof统计一下当前的文件打开数
lsof | grep foobar | wc -l
1690

1690,大于1024有点多了,接下来仔细看一下。

  1. lsof大概的逐条分析一下
lsof | grep foobar
blablabla...
blablabla...
blablabla...

既有文件,也有网络连接。不像是那种同时发起了大量网络连接造成的故障。这里算是PASS了。

检查limits.conf配置

走到这里,还没查出问题,就有点意外了,索性再检查一下limits.conf

cat /etc/security/limits.conf

*    soft    nofile    655360
*    hard    nofile    655360
*    soft    noproc    655360
*    hard    noproc    655360
*    soft    core      0
*    hard    core      0

都是655360,一眼看上去没有问题(但这里有个坑,稍后会提到)

检查各个profile配置

再检查各个profile的配置,例如.bash_profile里是不是手工设置了过小的ulimit,导致登录失败。

cat /etc/profile
cat /foobar/.bash_profile

都很正常,并没有添加多余的东西进去

监控系统secure日志

到这时都没发现出问题,只能监控系统日志/var/log/secure了。
一边监控,一边实行su - foobar

tail -f /var/log/secure
blablabla...

Mar 30 12:08:02 localhost crond[29226]: pam_limits(crond:session): unknown limit item 'noproc'

blablabla...

终于抓到一个问题:noproc参数是个什么鬼,应该是nproc才对吧,估计管理员当时是直接手撸的,没有复制粘帖。

于是赶紧修改limits.conf

vi /etc/security/limits.conf

*    soft    noproc    655360
*    hard    noproc    655360

改为

*    soft    nproc    655360
*    hard    nproc    655360

山穷水尽

解决完上面那个问题,以为这下可以su成功了吧,然而并没有,报错依旧。

于是继续监控/var/log/secure日志。现在报错变成了:

Mar 30 12:10:25 localhost su: pam_unix(su-l:session): session opened for user foobar by monitor(uid=0)
Mar 30 12:10:25 localhost su: pam_unix(su-l:session): session closed for user foobar

这种报错,相当于什么也没说啊。看来接下来,想要解决问题,只能靠猜了。

一通google之后,找到了这么一句话:

In Red Hat Enterprise Linux 6, there's a default setting in /etc/security/limits.d/90-nproc.conf. Change the default limit for all users or add a new limit for the affected user.

这个limits.d/90-nproc.conf之前从没有注意过,难道它会覆盖 limits.conf 吗?

cat /etc/security/limits.d/90-nproc.conf
*          soft    nproc     1024
root       soft    nproc     unlimited

这里的值是1024,尝试改大一点,碰碰运气:

vi /etc/security/limits.d/90-nproc.conf
*          soft    nproc     10240
root       soft    nproc     unlimited

然后su - foobar ,竟然成功了。

经验值+3

到此为止,两个坑都已经被填上了。耗时15分钟,经验值+3:

  1. 遇到类似问题,直接监控/var/log/secure,可以少走些弯路
  2. 注意/etc/security/limits.conf的参数拼写
  3. 竟然还有/etc/security/limits.d/90-nproc.conf这么个东西,且生效的时机诡异(只影响su,直接登录不受影响)

推荐阅读更多精彩内容