1.案例场景

  • 系统的用户 CPU 使用率(usr%)过高
  • 没有 CPU 使用率高的进程

2.案例环境

  • 本地系统:mac
  • docker:docker镜像-cpu使用率过高
  • 补充: 1.phpfpm容器要给权限 docker run --privileged ...; 2.进入phpfpm安装检查软件 apt install stress sysstat; 3.phpfpm内安装perfapt-get install -y linux-perf

3.操作分析

3.1 检查环境正常

在第二个中断,确认Nginx服务器正常启动,并发送100个请求检查Nginx性能

1
2
3
4
5
6
7
8
9
# ip地址是虚拟机的ip地址
$ curl http://127.0.0.1:10000/
# 并发 100 个请求测试 Nginx 性能,总共测试 1000 个请求
$ ab -c 100 -n 1000 http://127.0.0.1:10000/
# 打印
...
Requests per second:    130.19 [#/sec] (mean)
Time per request:       768.107 [ms] (mean)
...

3.2 压力测试

1
2
# 并发请求数为5,请求时间为10分钟(-t 600)
$ b -c 5 -t 600 http://192.168.0.10:10000/

3.3 分析

步骤1. 用top观察系统的cpu使用情况

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
...
Tasks:  20 total,   6 running,  14 sleeping,   0 stopped,   0 zombie
%Cpu(s): 62.3 us, 24.9 sy,  0.0 ni, 11.2 id,  0.0 wa,  0.0 hi,  1.6 si,  0.0 st
...

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
34256 daemon    20   0  227180  14296   8296 S   3.0   0.7   0:00.19 php-fpm
34261 daemon    20   0  227180  14232   8232 R   2.7   0.7   0:00.18 php-fpm
34269 daemon    20   0  227180  14232   8232 S   2.7   0.7   0:00.18 php-fpm
34272 daemon    20   0  227180  14232   8232 S   2.7   0.7   0:00.18 php-fpm
34283 daemon    20   0  227180  14232   8232 S   2.7   0.7   0:00.17 php-fpm
    1 root      20   0  227180  32524  26752 S   0.3   1.6   0:00.57 php-fpm
37036 daemon    20   0    4752    104      0 R   0.0   0.0   0:00.00 stress

分析:cpu使用率高,但是进程列表没有大的cpu使用进程,那为什么cou使用率高内?

步骤2. 用pidstat分析进程的CPU使用情况

1
2
3
4
5
6
7
8
# 间隔1s输出一组数据(按 Ctrl+C 结束)
$ pidstat 1
# 打印
Linux 4.19.76-linuxkit (78890ee58ed3) 	05/29/20 	_x86_64_	(4 CPU)

03:10:05      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

03:10:06      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

分析:发现进程的cpu使用率也不高

老炮儿分析:去运行top,观察一会儿,发现6个running状态的进程数,并且观察到php-fpm进程都处于Sleep状态;而处于running状态的进程却是今个stress

步骤3. 找一个stress进程进行分析 在怀疑性能工 具出问题前,最好还是先用其他工具交叉确认一下

1
2
3
4
# 分析pid进程cpu
$ pidstat -p <pid>
# 从所有进程中查找PID是pid的进程
$ ps aux | grep <pid>

这些进程在不停地重启,要么就是全 新的进程,这无非也就两个原因:

第一个原因,进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了。

第二个原因,这些进程都是短时进程,也就是在其他应用内部通过exec调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用top这种间隔时间比较长的工具发现(上面的案例,我们碰巧发现了)。

步骤4.pstree显示进程直接的关系

1
2
$ pstree | grep stress
php-fpm-+-4*[php-fpm---sh---stress---stress]

分析:stress是被php-fpm调用的子进程,并且进程数量不止一个(这里是 3 个)。找到父进程后,我们能进入app的内部分析了

1
2
3
4
5
6
# 拷贝源码到本地
$ docker cp phpfpm:/app .
# grep 查找看看是不是有代码在调用 stress 命令
$ grep stress -r app
app/index.php:// fake I/O with stress (via write()/unlink()).
app/index.php:$result = exec("/usr/local/bin/stress -t 1 -d 1 2&gt;&amp;1", $output, $status);

可以看到,果然是源码直接调用了stress,然后修改问题

3.4其他工具

perf 和 execsnoop

1
2
3
4
 # 记录性能事件,等待大约 15 秒后按 Ctrl+C 退出 
 $ perf record -g
 # 查看报告
 $ perf report
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Samples: 274K of event 'cpu-clock', Event count (approx.): 68743250000
      Self  Command      Shared Object         Symbol
-   17.48%  stress       libc-2.28.so          [.] random                                         ◆
   - 0.81% random                                                                                 ▒
      - 0.74% 0xffffffffa8800a34                                                                  ▒
         - 0.58% 0xffffffffa8003ad5                                                               ▒
              0xffffffffa8003358                                                                  ▒
-   15.19%  stress       libc-2.28.so          [.] random_r                                       ▒
   - 0.69% random_r                                                                               ▒
      - 0.62% 0xffffffffa8800a34                                                                  ▒
         - 0.50% 0xffffffffa8003ad5                                                               ▒
              0xffffffffa8003358                                                                  ▒
+    0.00%  swapper      [unknown]             [k] 0xffffffffa8800088                             ▒
+    0.00%  swapper      [unknown]             [k] 0xffffffffa8003c87

4.总结

  1. 分析性能问题时,最好能多工具结合分析 vmstat pidstat top ps pstree execsnoop
  2. 发现无法解释的cpu使用情况时:
  • 首先要想到有可能是短时应用导致的问题。
  • 应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过top等工具也不容易发现。
  • 应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用相当多的 CPU。