Skip to content

Latest commit

 

History

History
208 lines (140 loc) · 8.87 KB

1.一次从root用户su到qfpay用户失败的经历.md

File metadata and controls

208 lines (140 loc) · 8.87 KB

背景介绍

 工作中遇到这样一件事情,有一天工作的时候收到一个报警短信,短信内容为某个机器的负载过高到了30,习惯性地ssh登录到这个机器上看看什么情况,因为我是root权限,所以我一般通过root用户直接su到服务器部署的用户,但这一次不行,当我执行su - test的时候,遇到提示:

cannot set user id: Resource temporarily unavailable

自己的排查步骤:

  • 查看fd

首先想到的是不是这个用户的程序把fd给占满了,导致su进不去了,然后去看了/etc/security/limits.d/90nproc.conf这个文件,这是用户自定义配置limits的文件,看到test用户的fd上限为655350,已经挺大的了,然后再次确认了一下,看了/proc/sys/fs/file-nr,发现总的也是655350,使用的数量才为6000,明显没有用完啊,检查完毕,文件描述符没有问题.

  • 跟同事想了很久,看了很多参数,内存,CPU,等等都没有什么问题,后来就想到了用户的创建进程数,于是就先修改了/etc/security/limits.d/90nproc.conf中的用户的nproc参数,后来果然就好了,这里有一点要注意,修改这个配置文件不需要任何操作即可生效,重新登录即可,修改/etc/sysctl.conf才需要执行命令后生效.

按说到此为止这个问题就结束了,但是有没有感觉这样做等于什么都没学会呢?

最好的学习方式就是去深挖工作/生活中遇到的问题,并不断总结!

深挖过程

 从哪儿开始挖呢?当我解决这个问题后,通过root用户进去test用户后发现,这个用户下的进程并没有那么多,怎么去查看某个用户的所有进程呢?第一能想到的是列出所有进程通过grep找到某个用户的,有点low啊,看看比较好用的吧

方法一:
$ ps -u test u

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
test    25216  0.0  0.4 140832  2176 ?        S    16:00   0:00 sshd: test@pts/0
test    25217  0.3  0.8 141248  4348 pts/0    Ss   16:00   0:00 -zsh
roctestky    25350  0.0  0.3 151056  1868 pts/0    R+   16:01   0:00 ps -u test u
test    29318  0.0  0.3 220888  1804 ?        Ss   11月20   7:01 /home/test/supervisor/bin/python2 /home/test/supervisor/bin/supervisord -c /hom
test    29323  0.0  0.0  22596   340 ?        S    11月20   0:01 /home/test/shadowsocks/ss-local -c /home/test/shadowsocks/etc/shadowsocks.json

方法二:
$top -U test

16:03:28 up 24 days, 17:40,  1 user,  load average: 0.09, 0.05, 0.05
Tasks: 101 total,   1 running, 100 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.5 us,  0.2 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   498884 total,    43300 free,    62204 used,   393380 buff/cache
KiB Swap:  1048572 total,  1034664 free,    13908 used.   366336 avail Mem

test  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
25216 test     20   0  140832   2176    940 S   0.0  0.4   0:00.03 sshd: test@pts/0
25217 test     20   0  141248   4352   2228 S   0.0  0.9   0:00.21 -zsh
25516 test     20   0  157724   2336   1680 R   0.0  0.5   0:00.03 top -U test
29318 test     20   0  220888   1804    728 S   0.0  0.4   7:01.40 /home/test/supervisor/bin/python2 /home/test/supervisor/bin/supervisord -c /+
29323 test     20   0   22596    340    312 S   0.0  0.1   0:01.63 /home/test/shadowsocks/ss-local -c /home/test/s

上图只是介绍命令使用方法,不是真实数据,粗略计算了一下进程数,根本不够nproc的上限啊,那怎么回事儿呢?会不会是进程就启动起来后马上都退出了呢?应该不会吧,带着这个疑问我又去搜了一下这个问题的本身,哟呵,果然发现了什么东西:

The user fails to log in because an EAGAIN error occurs if the user's number of executing threads has reached the nproc resource limit.

Note: Despite the name, this is a limit on threads, not processes.

毁三观有没有,印象中npro是进程数啊,所以说多看看官方文档还是不错滴.这下问题就好解释了,进程数少的时候不代表线程数就少,那么怎么去看某个用户的所有线程数呢?接着看吧

# ps -u test -L | wc -l

996

# ps -u test | wc -l

67

通过下面的命令可以具体看到所有的线程,不仅仅是名称而是全部的执行命令,跟top c效果一样
#ps -u test -L u   


看出来了吧,ps的L参数就是显示线程的作用,默认不加该选项的话是显示进程

现在会了吧,一般项目中紧急遇到该问题后一般进不去普通用户,那就直接使用root用户直接执行这个命令查看.如果查看的结果大于nproc设置的上限,那么问题就很清晰了,上调一下该参数即可.如果说大于这个上限很多的话,就要考虑第二种情况了,是不是创建的线程数接近了系统能允许创建的总的线程数,怎么查看系统允许的总的线程数呢?

$ cat /proc/sys/kernel/thread-max

65535

听说htop很好用,这个时候就试了试它,但是发现了一个小小的问题,因为这次遇到的问题是关于线程数/进程数的,所以就比较了一下tophtop的tasks字段,发现了一些不同:

top

top - 16:45:24 up 351 days, 23:14,  2 users,  load average: 0.00, 0.02, 0.05
Tasks: 258 total,   3 running, 255 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1009276 total,   101616 free,   190892 used,   716768 buff/cache
KiB Swap:  2113532 total,  1461360 free,   652172 used.   565120 avail Mem

htop

top - 16:45:24 up 351 days, 23:14,  2 users,  load average: 0.00, 0.02, 0.05
Tasks: 43 total,   3 running, 255 sleeping,   0 stopped,   0 zombie

进程数为什么会不一样呢?我明明都是使用root启动的该命令,哪里出错了?再看看线程数,通过H来切换到显示线程数 上来:

top

top - 16:49:19 up 351 days, 23:18,  2 users,  load average: 0.00, 0.01, 0.05
Threads: 348 total,   2 running, 346 sleeping,   0 stopped,   0 zombie

htop

top - 16:49:19 up 351 days, 23:18,  2 users,  load average: 0.00, 0.01, 0.05
Threads: 89 total,   2 running, 346 sleeping,   0 stopped,   0 zombie

同样差别很大,那得好好查查了.我们都遇到过这样一种情况,在使用ps命令的时候经常会看到很多带着[]的一些进程,而且进程的PID很小:

$ ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2015 ?        00:23:31 /usr/lib/systemd/systemd --system --deserialize 23
root         2     0  0  2015 ?        00:00:04 [kthreadd]
root         3     2  0  2015 ?        00:03:57 [ksoftirqd/0]
root         7     2  0  2015 ?        00:00:00 [migration/0]
root         8     2  0  2015 ?        00:00:00 [rcu_bh]
root         9     2  0  2015 ?        00:00:00 [rcuob/0]
root        10     2  0  2015 ?        00:00:00 [rcuob/1]
root        11     2  0  2015 ?        00:00:00 [rcuob/2]

我猜测是htop少了部分内核的进程,是不是呢,下面我来验证一下,从网上查看得知带有[]的进程是内核进程,我们一般用户不会直接接触到它,这些进程有一个特点,这些进程的/proc/<pid>/cmdline文件是空的(僵尸进程也是,这里不考虑),利用这一点我写了一个小小的python脚本,计算了一下/proc目录下总的进程数和/proc/<pid>/cmdline不为空的进程数:

#!/usr/bin/env python3
import os
import sys


pids = []

for item in os.listdir("/proc"):
    try:
        int(item)
        pids.append(item)
    except:
        pass

n = 0

for pid in pids:
    cmdline = open("/proc/" + pid + "/cmdline").read()
    if cmdline:
        n += 1

print(len(pids))
print(n)

执行后返回结果为259和43, 然后分别执行tophtop,不出所料,果然是这种情况,一般情况下内核线程对我们没有用处,我们只需要考虑用户自己的进程即可,所以结论是htop还是比较人性化的,大爱!那怎么查看某个进程的线程数呢?

方法一:
cat /proc/7502/status

Name:   mysqld
State:  S (sleeping)
Tgid:   5877
Pid:    5877
PPid:   1
……………………省略
Threads: 107
……………………省略

方法二:
$ pstree -p 40322

mysqld_safe(40322)───mysqld(40518)─┬─{mysqld}(40519)
                                   ├─{mysqld}(40520)
                                   ├─{mysqld}(40521)
                                   ├─{mysqld}(40522)
                                   ├─{mysqld}(40523)
                                   ├─{mysqld}(40524)
                                   ├─{mysqld}(40525)
                                   ├─{mysqld}(40526)
                                   ├─{mysqld}(40527)
                                   ├─{mysqld}(40528)
                                   ├─{mysqld}(40529)

到此为止,暂时告一段落吧!

参考文档

红帽官网关于这个问题的答案