cpu到达100% 但是找不到使用cpu的进程
一般分析cpu使用率:通过使用 top、vmstat、pidstat 等工具,排查高 CPU 使用率的进程,然后再使用 perf top 工具,定位应用内部函数的问题。
但是!不是所有cpu过高都是这样分析的,这只是一般情况下可以这样分析。什么是一般情况?简单说,通常可以根据工具,就可以找到cpu占有过高的进程!
通过top命令我们知道,系统cpu使用率基本包括
- 进程用户状态的运行
- 内核状态的运行
- 中断处理的线程
- 等待I/O的线程
- 内核线程
以前看到cpu过高时,简单的以为是某一个进程占用过大导致的,其实不一定,系统CPU过高,不一定是进程引起的,还有可能是IO过高或者阻塞引起的,也有可能是中断进程引起的,多方面原因分析
如下一个案例
使用TOP命令
$ top
top - 04:58:24 up 14 days, 15:47, 1 user, load average: 3.39, 3.82, 2.74
Tasks: 149 total, 6 running, 93 sleeping, 0 stopped, 0 zombie
%Cpu(s): 77.7 us, 19.3 sy, 0.0 ni, 2.0 id, 0.0 wa, 0.0 hi, 1.0 si, 0.0 st
KiB Mem : 8169348 total, 2543916 free, 457976 used, 5167456 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 7363908 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6947 systemd+ 20 0 33104 3764 2340 S 4.0 0.0 0:32.69 nginx
6882 root 20 0 12108 8360 3884 S 2.0 0.1 0:31.40 docker-containe
15465 daemon 20 0 336696 15256 7576 S 2.0 0.2 0:00.62 php-fpm
15466 daemon 20 0 336696 15196 7516 S 2.0 0.2 0:00.62 php-fpm
15489 daemon 20 0 336696 16200 8520 S 2.0 0.2 0:00.62 php-fpm
6948 systemd+ 20 0 33104 3764 2340 S 1.0 0.0 0:00.95 nginx
15006 root 20 0 1168608 65632 37536 S 1.0 0.8 9:51.09 dockerd
15476 daemon 20 0 336696 16200 8520 S 1.0 0.2 0:00.61 php-fpm
15477 daemon 20 0 336696 16200 8520 S 1.0 0.2 0:00.61 php-fpm
24340 daemon 20 0 8184 1616 536 R 1.0 0.0 0:00.01 stress
24342 daemon 20 0 8196 1580 492 R 1.0 0.0 0:00.01 stress
24344 daemon 20 0 8188 1056 492 R 1.0 0.0 0:00.01 stress
24347 daemon 20 0 8184 1356 540 R 1.0 0.0 0:00.01 stress
...
这次从头开始看 top 的每行输出,Tasks 这一行看起来有点奇怪,就绪队列中居然有 6 个 Running 状态的进程(6 running),是不是有点多呢?
然后用 pidstat 命令看一下它的 CPU 使用情况:
$ pidstat -p 24344
16:14:55 UID PID %usr %system %guest %wait %CPU CPU Command
奇怪,居然没有任何输出。难道是 pidstat 命令出问题了吗?我们在终端里运行下面的命令,看看 24344 进程的状态:
# 从所有进程中查找 PID 是 24344 的进程
$ ps aux | grep 24344
root 9628 0.0 0.0 14856 1096 pts/0 S+ 16:15 0:00 grep --color=auto 24344
还是没有输出。现在终于发现问题,原来这个进程已经不存在了,所以 pidstat 就没有任何输出。既然进程都没了,那性能问题应该也跟着没了吧
然后再一次top一下
$ top
...
%Cpu(s): 80.9 us, 14.9 sy, 0.0 ni, 2.8 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6882 root 20 0 12108 8360 3884 S 2.7 0.1 0:45.63 docker-containe
6947 systemd+ 20 0 33104 3764 2340 R 2.7 0.0 0:47.79 nginx
3865 daemon 20 0 336696 15056 7376 S 2.0 0.2 0:00.15 php-fpm
6779 daemon 20 0 8184 1112 556 R 0.3 0.0 0:00.01 stress
...
好像又错了。结果还跟原来一样,用户 CPU 使用率还是高达 80.9%,系统 CPU 接近 15%,而空闲 CPU 只有 2.8%,Running 状态的进程有 Nginx、stress 等。
可是,刚刚我们看到 stress 进程不存在了,怎么现在还在运行呢?再细看一下 top 的输出,原来,这次 stress 进程的 PID 跟前面不一样了,原来的 PID 24344 不见了,现在的是 6779。
那么问题来了,stress这个进程再不断的变换PID,是什么原因呢?
一个进程不断的变换Pid号,无非两种原因
第一个原因:进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了
第二个原因:这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,很难用 top 这种间隔时间比较长的工具发现
通过这两种原因,看来,top命令也不是万能的,也会有些速度快的进程逃过他的检查(天下武功,唯快不破)
回到问题:stress这个进程不断的变换PID,又占用用cpu资源,导致cpu过高,这个时候,找到它的父进程,来进行下一步分析
使用pstree命令来看进程关系,找到它的父进程!
看看是不是父进程里有什么调用问题,看看父进程的源码
一大部分可能是————————————————
由于权限错误,大量的 stress 进程在启动时初始化失败,进而导致用户 CPU 使用率的升高。或者是二进制文件里有对stress有大量的调用循环。
问题总结:
碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题,比如有可能是下面这两种情况
- 应用里直接调用了其他二进制程序,这些程序通常会运行时间很短,速度非常快,通过top等其他工具不一定能查询的到
- 应用本身就在不停的崩溃重启,而启动过程的资源初始化,很可能会占用大量的CPU,而且这类进程,PID会不断变更,通常只能通过pstree或者execsnoop找到它的父进程,从父进程所在的应用里查找,找到问题所在,排查问题。