工作中遇到这样一件事情,有一天工作的时候收到一个报警短信,短信内容为某个机器的负载过高到了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
很好用,这个时候就试了试它,但是发现了一个小小的问题,因为这次遇到的问题是关于线程数/进程数的,所以就比较了一下top
和htop
的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, 然后分别执行top
和htop
,不出所料,果然是这种情况,一般情况下内核线程对我们没有用处,我们只需要考虑用户自己的进程即可,所以结论是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)
到此为止,暂时告一段落吧!