linux性能评估-cpu案例操作篇

1.平均负载案例分析

预先安装 stress 和 sysstat 包。(yum install -y stress , yum install -y sysstat)
stress 是一个 Linux 系统压力测试工具,这里我们用作异常进程模拟平均负载升高的场景。
sysstat 包含了常用的 Linux 性能工具,用来监控和分析系统的性能。我们的案例会用到这个包的两个命令 mpststat 和 pidstat。

  • mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标。
  • pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。

场景一:CPU 密集型进程

我们在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:

$ stress --cpu 1 --timeout 600

接着,在第二个终端运行 uptime 查看平均负载的变化情况:

[root@CESHI_Game_YALI_26 ceshi]# uptime

17:37:54 up 277 days,  2:273 users,  load average: 0.99, 0.69, 0.31

在第三个终端运行 mpstat 查看 CPU 使用率的变化情况:

# -P ALL 表示监控所有 CPU,后面数字 5 表示间隔 5 秒后输出一组数据

[root@CESHI_Game_YALI_26 ceshi]# mpstat -P ALL 5

Linux 2.6.32-642.6.2.el6.x86_64 (CESHI_Game_YALI_26)    02/22/2019  _x86_64_    (4 CPU)

05:36:53 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle

05:36:58 PM  all   25.06    0.00    0.00    0.00    0.00    0.00    0.00    0.00   74.94

05:36:58 PM    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00

05:36:58 PM    1    0.20    0.00    0.00    0.00    0.00    0.00    0.00    0.00   99.80

05:36:58 PM    2    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

05:36:58 PM    3    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00

分析:从终端二中可以看到,1 分钟的平均负载会慢慢增加到 0.99,而从终端三中还可以看到,正好有一个 CPU 的使用率为 100%,但它的 iowait 只有 0。这说明,平均负载的升高正是由于 CPU 使用率为 100% 。
那么,到底是哪个进程导致了 CPU 使用率为 100% 呢?可以使用 pidstat 来查询:

# 间隔 5 秒后输出一组数据

# pidstat -u 5 1

Linux 2.6.32-642.6.2.el6.x86_64 (CESHI_Game_YALI_26)    02/22/2019  _x86_64_    (4 CPU)

05:47:17 PM       PID    %usr %system  %guest    %CPU   CPU  Command

05:47:22 PM        19    0.00    0.20    0.00    0.20     0  events/0

05:47:22 PM     15345  100.00    0.00    0.00  100.00     3  stress

05:47:22 PM     27162    0.00    0.20    0.00    0.20     2  mail

05:47:22 PM     32008    0.20    0.20    0.00    0.40     2  telegraf

Average:          PID    %usr %system  %guest    %CPU   CPU  Command

Average:           19    0.00    0.20    0.00    0.20     -  events/0

Average:        15345  100.00    0.00    0.00  100.00     -  stress

Average:        27162    0.00    0.20    0.00    0.20     -  mail

Average:        32008    0.20    0.20    0.00    0.40     -  telegraf

从这里可以明显看到,stress 进程的 CPU 使用率为100%。

场景二:I/O密集型进程

首先还是运行 stress 命令,但这次模拟 I/O压力,即不停地执行 sync:

# stress -i 1 --timeout 600

还是在第二个终端运行 uptime 查看平均负载的变化情况:

[root@CESHI_Game_YALI_26 ceshi]# uptime

18:14:43 up 277 days,  3:043 users,  load average: 1.11, 0.55, 0.31

然后,第三个终端运行 htop 查看 CPU 使用率的变化情况:

比如cpu密集型的应用,它的负载颜色是绿色偏高,iowait的操作,它的负载颜色是红色偏高等等,此案例的查看结果是红色偏高,正是iowait的操作导致的。根据这些指标再用htop的sort就很容易定位到有问题的进程。按上下键选择进程之后,按s,按s:用strace追踪进程的系统调用。

场景三:大量进程的场景

当系统中运行进程超出 CPU 运行能力时,就会出现等待 CPU 的进程。
我们还是使用 stress,但这次模拟的是 8 个进程:

$ stress -c 8 --timeout 600

由于系统只有 4个 CPU,明显比 8 个进程要少得多,因而,系统的 CPU 处于严重过载状态,平均负载高达 7.74.

[root@CESHI_Game_YALI_26 ceshi]# uptime

14:36:30 up 277 days, 23:263 users,  load average: 7.74, 3.85, 1.51

在第三个终端中,输入htop,查看CPU使用情况,可以看出绿色显示4个CPU已经使用完,出现了CPU过载。

所以,在理解平均负载时,也要注意:

  • 平均负载高有可能是 CPU 密集型进程导致的;
  • 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O更繁忙了;
  • 当发现负载高的时候,你可以使用 mpstat、pidstat,htop等工具,辅助分析负载的来源。

场景二和场景三没有使用pidstat查看,是因为CentOS默认的sysstat稍微有点老,不显示%wait的问题,所以用的htop查看的。

2.CPU 上下文切换案例

2.1怎么查看系统的上下文切换情况

vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。

# 每隔 5 秒输出 1 组数据

[root@CESHI_Game_YALI_26 ceshi]# vmstat 5

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

 0  0 1221036 6357068 153540 1062220    1    1     2     7    0    0  0  0 99  0  0

 0  0 1221036 6357052 153540 1062240    0    0     0     5  129  200  0  0 100  0  0

 0  0 1221036 6357052 153540 1062240    0    0     0     0   89  149  0  0 100  0  0

  • cs(context switch)是每秒上下文切换的次数。
  • in(interrupt)则是每秒中断的次数。
  • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
  • b(Blocked)则是处于不可中断睡眠状态的进程数。

2.2查看每个进程上下文切换的情况

[root@CESHI_Game_YALI_26 ceshi]# pidstat -w 5

Linux 2.6.32-642.6.2.el6.x86_64 (CESHI_Game_YALI_26)    02/23/2019  _x86_64_    (4 CPU)

03:18:47 PM       PID   cswch/s nvcswch/s  Command

03:18:52 PM         7      0.20      0.00  migration/1

03:18:52 PM         9      0.40      0.00  ksoftirqd/1

03:18:52 PM        17      0.20      0.00  ksoftirqd/3

  • cswch ,表示每秒自愿上下文切换的次数。
  • nvcswch ,表示每秒非自愿上下文切换的次数。
  • 所谓自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。
  • 而非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。

2.3 案例实操

安装sysbench(yum install -y sysbench)

在第一个终端里运行 sysbench ,模拟系统多线程调度的瓶颈:

# 以 10 个线程运行 5 分钟的基准测试,模拟多线程切换的问题

sysbench --threads=10 --max-time=300 threads run

接着,在第二个终端运行 vmstat ,观察上下文切换情况。

[root@CESHI_Game_YALI_26 ceshi]# vmstat 1

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----

 r  b   swpd   free   buff  cache   si   so    bi    bo   in cs us sy  id  wa  st

 5  0 1221036 6336044 154056 1080128    1    1     2     7    0    0  0  0 99  0  0

 7  0 1221036 6336028 154056 1080128    0    0     0     0 24446 2328677 19 70 11  0  0

 7  0 1221036 6336028 154056 1080128    0    0     0     0 29130 2355960 16 71 13  0  0

  • cs 列的上下文切换次数已经到了232万,同时,观查其他指标:
  • r列:就绪队列到了7,远远超过了CPU的个数4,所以肯定会有CPU竞争。
  • us(user)列和sy(system)列:这两列的CPU使用加起来到了90%,其中sy列的使用率到了71%,说明CPU主要被内核占用。
  • in列:中断次数上升了2万多,说明中断也是潜在的问题。

综合这几个指标,我们可以知道,系统的就绪队列过长,也就是正在运行和等待 CPU 的进程数过多,导致了大量的上下文切换,而上下文切换又导致了系统 CPU 的占用率升高。
分析是什么进程导致:

pidstat -wt参数表示输出线程的上下文切换指标:

# 每隔 1 秒输出一组数据(需要 Ctrl+C 才结束)

# -wt 参数表示输出线程的上下文切换指标

$ pidstat -wt 1

Linux 2.6.32-642.6.2.el6.x86_64 (CESHI_Game_YALI_26)    02/23/2019  _x86_64_    (4 CPU)

03:30:31 PM      TGID       TID   cswch/s nvcswch/s  Command

03:30:32 PM         -     31593  51816.67 199325.49  |__sysbench

03:30:32 PM         -     31594  50935.29 183059.80  |__sysbench

03:30:32 PM         -     31595  48006.86 204500.00  |__sysbench

03:30:32 PM         -     31596  51797.06 172247.06  |__sysbench

03:30:32 PM         -     31597  48173.53 188500.98  |__sysbench

03:30:32 PM         -     31598  47034.31 193852.94  |__sysbench

03:30:32 PM         -     31599  48339.22 219121.57  |__sysbench

03:30:32 PM         -     31600  57043.14 209324.51  |__sysbench

03:30:32 PM         -     31601  46477.45 205529.41  |__sysbench

03:30:32 PM         -     31602  55468.63 178434.31  |__sysbench

看来,上下文切换罪魁祸首,还是过多的 sysbench 线程。

分析中断问题的导致:
既然是中断,它只发生在内核态,而
pidstat 只是一个进程的性能分析工具,并不提供任何关于中断的详细信息。没错,那就是从 /proc/interrupts
这个只读文件中读取。/proc 实际上是 Linux 的一个虚拟文件系统,用于内核空间与用户空间之间的通信。/proc/interrupts
就是这种通信机制的一部分,提供了一个只读的中断使用情况。

# -d 参数表示高亮显示变化的区域

$ watch -d cat /proc/interrupts

观察一段时间,你可以发现,变化速度最快的是重调度中断(RES),这个中断类型表示,唤醒空闲状态的
CPU 来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同CPU
的机制,通常也被称为处理器间中断(Inter-Processor Interrupts,IPI)。

如果最开始时,我们只用了 pidstat 观测,这些很严重的上下文切换线程,压根儿就发现不了了。
这个数值其实取决于系统本身的
CPU
性能。在我看来,如果系统的上下文切换次数比较稳定,那么从数百到一万以内,都应该算是正常的。但当上下文切换次数超过一万次,或者切换次数出现数量级的增长时,就很可能已经出现了性能问题。所以,这里的中断升高还是因为过多任务的调度问题,跟前面上下文切换次数的分析结果是一致的。

所以:

  • 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
  • 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈;
  • 中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。

3.CPU使用率的案例

3.1CPU 使用率很高,但为啥却找不到高 CPU 的应用?

当你发现系统的 CPU 使用率很高的时候,不一定能找到相对应的高 CPU 使用率的进程。
首先要观察CPU的使用情况:使用top命令:
如果在top命令和pidstat
命令中都查看不到使用CPU较高的进程,那么需要从 CPU 使用率不高但处于 Running 状态的进程入手,找出了可疑之处,最终通过 perf
record -g 和 perf report 进行排查。发现原来是短时进程在捣鬼。

改案例需要在虚拟机中进行。预先安装 docker、sysstat、perf、ab 等工具,如 apt install docker.io sysstat linux-tools-common apache2-utils 

1.首先,我们在第一个终端,执行下面的命令运行 Nginx 和 PHP 应用:

$ docker run --name nginx -p 10000:80 -itd feisky/nginx:sp

$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:sp

2.然后,在第二个终端,使用 curl 访问 http://[VM1 的 IP]:10000,确认 Nginx 已正常启动。你应该可以看到 It works! 的响应。

# 172.16.109.245 是第一台虚拟机的 IP 地址

$ curl http://172.16.109.245:10000/

It works!

3.接着,我们来测试一下这个 Nginx 服务的性能。在第二个终端运行下面的 ab 命令。要注意,与上次操作不同的是,这次我们需要并发 100 个请求测试 Nginx 性能,总共测试 1000 个请求。

# 并发 100 个请求测试 Nginx 性能,总共测试 1000 个请求

$ ab -c 100 -n 1000 http://172.16.109.245:10000/

This is ApacheBench, Version 2.3 <$Revision: 1706008 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd,

...

Requests per second:    87.86 [#/sec] (mean)

Time per request:       1138.229 [ms] (mean)

...

从 ab 的输出结果我们可以看到,Nginx 能承受的每秒平均请求数,只有 87 多一点,是不是感觉它的性能有点差呀。那么,到底是哪里出了问题呢?我们再用 top 和 pidstat 来观察一下。

4.这次,我们在第二个终端,将测试的并发请求数改成 5,同时把请求时长设置为 10 分钟(-t 600)。这样,当你在第一个终端使用性能分析工具时, Nginx 的压力还是继续的。
继续在第二个终端运行 ab 命令:

$ ab -c 5 -t 600 http://172.16.109.245:10000/

5.然后,我们在第一个终端运行 top 命令,观察系统的 CPU 使用情况:

$ top

...

%Cpu(s): 80.8 us, 15.1 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    8456   5052   3884 S   2.7  0.1   0:04.78 docker-containe

 6947 systemd+  20   0   33104   3716   2340 S   2.7  0.0   0:04.92 nginx

 7494 daemon    20   0  336696  15012   7332 S   2.0  0.2   0:03.55 php-fpm

 7495 daemon    20   0  336696  15160   7480 S   2.0  0.2   0:03.55 php-fpm

10547 daemon    20   0  336696  16200   8520 S   2.0  0.2   0:03.13 php-fpm

10155 daemon    20   0  336696  16200   8520 S   1.7  0.2   0:03.12 php-fpm

10552 daemon    20   0  336696  16200   8520 S   1.7  0.2   0:03.12 php-fpm

15006 root      20   0 1168608  66264  37536 S   1.0  0.8   9:39.51 dockerd

 4323 root      20   0       0      0      0 I   0.3  0.0   0:00.87 kworker/u4:1

...

观察 top 输出的进程列表可以发现,CPU 使用率最高的进程也只不过才 2.7%,看起来并不高。
然而,再看系统 CPU 使用率( %Cpu )这一行,你会发现,系统的整体 CPU 使用率是比较高的:用户 CPU 使用率(us)已经到了 80%,系统 CPU 为 15.1%,而空闲 CPU (id)则只有 2.8%。

为什么用户 CPU 使用率这么高呢?我们再重新分析一下进程列表,看看有没有可疑进程:
docker-containerd 进程是用来运行容器的,2.7% 的 CPU 使用率看起来正常;
Nginx 和 php-fpm 是运行 Web 服务的,它们会占用一些 CPU 也不意外,并且 2% 的 CPU 使用率也不算高;
再往下看,后面的进程呢,只有 0.3% 的 CPU 使用率,看起来不太像会导致用户 CPU 使用率达到 80%。
那就奇怪了,明明用户
CPU 使用率都 80% 了,可我们挨个分析了一遍进程列表,还是找不到高 CPU 使用率的进程。看来 top
是不管用了,那还有其他工具可以查看进程 CPU 使用情况吗?不知道你记不记得我们的老朋友 pidstat,它可以用来分析进程的 CPU
使用情况。

6.接下来,我们还是在第一个终端,运行 pidstat 命令:

# 间隔 1 秒输出一组数据(按 Ctrl+C 结束)

$ pidstat 1

...

04:36:24      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

04:36:25        0      6882    1.00    3.00    0.00    0.00    4.00     0  docker-containe

04:36:25      101      6947    1.00    2.00    0.00    1.00    3.00     1  nginx

04:36:25        1     14834    1.00    1.00    0.00    1.00    2.00     0  php-fpm

04:36:25        1     14835    1.00    1.00    0.00    1.00    2.00     0  php-fpm

04:36:25        1     14845    0.00    2.00    0.00    2.00    2.00     1  php-fpm

04:36:25        1     14855    0.00    1.00    0.00    1.00    1.00     1  php-fpm

04:36:25        1     14857    1.00    2.00    0.00    1.00    3.00     0  php-fpm

04:36:25        0     15006    0.00    1.00    0.00    0.00    1.00     0  dockerd

04:36:25        0     15801    0.00    1.00    0.00    0.00    1.00     1  pidstat

04:36:25        1     17084    1.00    0.00    0.00    2.00    1.00     0  stress

04:36:25        0     31116    0.00    1.00    0.00    0.00    1.00     0  atopacctd

...

观察一会儿,你是不是发现,所有进程的 CPU 使用率也都不高啊,最高的 Docker 和 Nginx 也只有 4% 和 3%,即使所有进程的 CPU 使用率都加起来,也不过是 21%,离 80% 还差得远呢!

7.现在,我们回到第一个终端,重新运行 top 命令,并观察一会儿:

$ top

top - 04:58:24 up 14 days, 15:471 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),是不是有点多呢?
回想一下 ab 测试的参数,并发请求数是 5。再看进程列表里, php-fpm 的数量也是 5,再加上 Nginx,好像同时有 6 个进程也并不奇怪。但真的是这样吗?
再仔细看进程列表,这次主要看
Running(R) 状态的进程。你有没有发现, Nginx 和所有的 php-fpm 都处于 Sleep(S)状态,而真正处于
Running(R)状态的,却是几个 stress 进程。这几个 stress 进程就比较奇怪了,需要我们做进一步的分析。

8.我们还是使用 pidstat 来分析这几个进程,并且使用 -p 选项指定进程的 PID。首先,从上面 top 的结果中,找到这几个进程的 PID。比如,先随便找一个 24344,然后用 pidstat 命令看一下它的 CPU 使用情况:

$ pidstat -p 24344

16:14:55      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

9.奇怪,居然没有任何输出。在怀疑性能工具出问题前,最好还是先用其他工具交叉确认一下,。那用什么工具呢? ps 应该是最简单易用的。我们在终端里运行下面的命令,看看 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

10.还是没有输出。现在终于发现问题,原来这个进程已经不存在了,所以 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

...

11.好像又错了。结果还跟原来一样,用户 CPU 使用率还是高达 80.9%,系统 CPU 接近 15%,而空闲 CPU 只有 2.8%,Running 状态的进程有 Nginx、stress 等。
可是,刚刚我们看到 stress 进程不存在了,怎么现在还在运行呢?再细看一下 top 的输出,原来,这次 stress 进程的 PID 跟前面不一样了,原来的 PID 24344 不见了,现在的是 6779。
进程的 PID 在变,这说明什么呢?在我看来,要么是这些进程在不停地重启,要么就是全新的进程,这无非也就两个原因:

  • 第一个原因,进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了。
  • 第二个原因,这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用 top 这种间隔时间比较长的工具发现(上面的案例,我们碰巧发现了)。

至于 stress,我们前面提到过,它是一个常用的压力测试工具。它的 PID 在不断变化中,看起来像是被其他进程调用的短时进程。要想继续分析下去,还得找到它们的父进程。
12.要怎么查找一个进程的父进程呢?没错,用 pstree 就可以用树状形式显示所有进程之间的关系:

$ pstree | grep stress

        |-docker-containe-+-php-fpm-+-php-fpm---sh---stress

        |         |-3*[php-fpm---sh---stress---stress]

从这里可以看到,stress 是被 php-fpm 调用的子进程,并且进程数量不止一个(这里是 3 个)。找到父进程后,我们能进入 app 的内部分析了。
分析原因:
perf 工具,它可以用来分析 CPU 性能事件,用在这里就很合适。依旧在第一个终端中运行 perf record -g 命令 ,并等待一会儿(比如 15 秒)后按 Ctrl+C 退出。然后再运行 perf report 查看报告:

# 记录性能事件,等待大约 15 秒后按 Ctrl+C 退出

$ perf record -g

# 查看报告

$ perf report -g

结束案例:

$ docker rm -f nginx phpfpm

小结:
碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题,比如有可能是下面这两种情况。

  • 第一,应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过 top 等工具也不容易发现。
  • 第二,应用本身在不停地崩溃重启,而启动过程的资源初始化,很可会占用相当多的 CPU。

3.2 等待 I/O 的 CPU的使用(多进程 I/O 的案例)

进程状态:当 iowait 升高时,进程很可能因为得不到硬件的响应,而长时间处于不可中断状态。从 ps 或者 top 命令的输出中,你可以发现它们都处于 D 状态,也就是不可中断状态。
首先使用top命令。查看系统的各个指标:

问题一:iowait升高
问题二:僵尸进程不断增多

首先看问题一:iowait问题分析
首先、使用工具dstat 进程查看,它的好处是,可以同时查看 CPU 和 I/O 这两种资源的使用情况,便于对比分析。

# 间隔 1 秒输出 10 组数据

$ dstat 1 10

从 dstat 的输出,我们可以看到,每当 iowait 升高(wai)时,磁盘的读请求(read)都会很大。这说明iowait 的升高跟磁盘的读请求有关,很可能就是磁盘读导致的。
到底是哪个进程在读磁盘呢?我们在top中可以看到有D状态的不可中断进程很可疑,我们来分析一下:

第二、使用pidstat分析D状态的进程:

# -d 展示 I/O 统计数据,-p 指定进程号,间隔 1 秒输出 3 组数据

# pidstat -d -p 116712 1 3

kB_rd 表示每秒读的 KB 数, kB_wr 表示每秒写的 KB 数,iodelay 表示 I/O 的延迟(单位是时钟周期)。它们都是 0,那就表示此时没有任何的读写,说明问题不是 116712进程导致的。
第三、使用pidstat 去掉-p参数,查看所有进程的IO情况:

# 间隔 1 秒输出多组数据 (这里是 20 组)

pidstat -d 1 20

观察一会儿可以发现,的确是 app 进程在进行磁盘读,并且每秒读的数据有 32 MB,看来就是 app 的问题。
第四、app 进程到底在执行啥 I/O 操作呢?

  • strace 正是最常用的跟踪进程系统调用的工具。

# strace -p 116911

结果可以看到没有权限。使用ps查看为啥没有权限?

ps aux | grep 116921

可以看到该进程已经变成了僵尸进程,所以没有权限查看。

  • 使用perf record -g 工具进行分析:

#等待20秒后,按ctrl+C 停止

perf record -g

  • 然后使用perf report -g 查看:

这个图里的 swapper 是内核中的调度进程,可以先忽略。
app
的确在通过系统调用 sys_read() 读取数据。并且从 new_sync_read 和 blkdev_direct_IO
能看出,进程正在对磁盘进行直接读,也就是绕过系统缓存,每个读请求都会从磁盘直接读,这就可以解释我们观察到的 iowait 升高了。
小结:

  • 碰到 iowait 升高时,需要先用 dstat、pidstat 等工具,确认是不是磁盘 I/O 的问题,然后再找是哪些进程导致了 I/O。
  • 等待 I/O 的进程一般是不可中断状态,所以用 ps 命令找到的 D 状态(即不可中断状态)的进程,多为可疑进程。但这个案例中,在 I/O 操作后,进程又变成了僵尸进程,所以不能用strace 直接分析这个进程的系统调用。
  • 这种情况下,我们用了 perf 工具来分析系统的 CPU 时钟事件,最终发现是直接 I/O 导致的问题。

4.系统的软中断CPU使用率升高,该怎么办?

预先安装 docker、sysstat、sar 、hping3、tcpdump 等工具,比如 apt-get install docker.io sysstat hping3 tcpdump。

  • sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。
  • hping3 是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙测试等。
  • tcpdump 是一个常用的网络抓包工具,常用来分析各种网络问题。

本次案例用到两台虚拟机。你可以看到,其中一台虚拟机运行 Nginx ,用来模拟待分析的 Web 服务器;而另一台当作 Web 服务器的客户端,用来给 Nginx 增加压力请求。使用两台虚拟机的目的,是为了相互隔离,避免“交叉感染”。
同以前的案例一样,下面的所有命令都默认以 root 用户运行,如果你是用普通用户身份登陆系统,请运行 sudo su root 命令切换到 root 用户。
操作和分析
安装完成后,我们先在第一个虚拟机,执行下面的命令运行案例,也就是一个最基本的 Nginx 应用:

# 运行 Nginx 服务并对外开放 80 端口

$ docker run -itd --name=nginx -p 80:80 nginx

然后,在第二个虚拟机,使用 curl 访问 Nginx 监听的端口,确认 Nginx 正常启动。假设172.16.109.245 是 Nginx 所在虚拟机的 IP 地址,运行 curl 命令后你应该会看到下面这个输出界面:

$ curl http://172.16.109.245/

<!DOCTYPE html>

<html>

<head>

<title>Welcome to nginx!</title>

...

接着,还是在第二个虚拟机,我们运行 hping3 命令,来模拟 Nginx 的客户端请求:

# -S 参数表示设置 TCP 协议的 SYN(同步序列号),-p 表示目的端口为 80

# -i u100 表示每隔 100 微秒发送一个网络帧

# 注:如果你在实践过程中现象不明显,可以尝试把 100 调小,比如调成 10 甚至 1

$ hping3 -S -p 80 -i u100 172.16.109.245

现在我们再回到第一个虚拟机,你应该发现了异常。是不是感觉系统响应明显变慢了,即便只是在终端中敲几个回车,都得很久才能得到响应?这个时候应该怎么办呢?

虽然在运行 hping3 命令时,这是一个 SYN FLOOD 攻击,你肯定也会想到从网络方面入手,来分析这个问题。不过,在实际的生产环境中,没人直接告诉你原因。所以希望你把 hping3 模拟 SYN FLOOD 这个操作暂时忘掉,然后重新从观察到的问题开始,分析系统的资源使用情况,逐步找出问题的根源。

那么,该从什么地方入手呢?刚才我们发现,简单的 SHELL 命令都明显变慢了,先看看系统的整体资源使用情况应该是个不错的注意,比如执行下 top 看看是不是出现了 CPU 的瓶颈。我们在第一个终端运行 top 命令,看一下系统整体的资源使用情况。

top - 03:32:44 up  3:501 user,  load average: 0.75, 0.98, 0.98

Tasks: 287 total,   2 running, 216 sleeping,   0 stopped,   0 zombie

%Cpu0  :  4.0 us,  1.7 sy,  0.0 ni, 94.0 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st

%Cpu1  :  1.0 us,  0.3 sy,  0.0 ni, 49.2 id,  0.0 wa,  0.0 hi, 49.5 si,  0.0 st

KiB Mem :  4025720 total,  2419400 free,  1186524 used,   419796 buff/cache

KiB Swap:   969960 total,   551012 free,   418948 used.  2558736 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                               

    18 root      20   0       0      0      0 R   5.0  0.0  63:08.96 ksoftirqd/1

  1583 xhong     20   0 3394648 131844  39900 S   2.3  3.3   1:11.93 gnome-shell                                                                                                                           

  1450 xhong     20   0  418176  41028  11544 S   2.0  1.0   0:37.07 Xorg                                                                                                                                  

  1948 xhong     20   0  803616  28288  17176 S   1.7  0.7   0:18.58 gnome-terminal-                                                                                                                       

 33806 root      20   0   51340   3880   3124 R   1.0  0.1   0:00.11 top                                                                                                                                   

  2186 root      20   0 1099276  12968   6344 S   0.3  0.3   0:16.79 docker-containe                                                                                                                       

     1 root      20   0  159936   5608   3772 S   0.0  0.1   0:05.44 systemd                                                                                                                                                                                                                                               

我们从第一行开始,逐个看一下:

  • 平均负载在1左右,就绪队列里面有2个进程(2 running)。
  • 每个 CPU 的使用率都挺低,si: 处理软件中断的CPU时间是49.5%
  • 再看进程列表,CPU 使用率最高的进程也只有 5%,还是不高呀。

根据上一期的内容,既然软中断可能有问题,那你先要知道,究竟是哪类软中断的问题。停下来想想,上一节我们用了什么方法,来判断软中断类型呢?没错,还是 proc 文件系统。观察 /proc/softirqs 文件的内容,你就能知道各种软中断类型的次数。

不过,这里的各类软中断次数,又是什么时间段里的次数呢?它是系统运行以来的累积中断次数。所以我们直接查看文件内容,得到的只是累积中断次数,对这里的问题并没有直接参考意义。因为,这些中断次数的变化速率才是我们需要关注的。

那什么工具可以观察命令输出的变化情况呢?我想你应该想起来了,在前面案例中用过的 watch 命令,就可以定期运行一个命令来查看输出;如果再加上 -d 参数,还可以高亮出变化的部分,从高亮部分我们就可以直观看出,哪些内容变化得更快。

比如,还是在第一个虚拟机,我们运行下面的命令:

$ watch -d cat /proc/softirqs

                    CPU0       CPU1

          HI:          0          0

       TIMER:    1083906    2368646

      NET_TX:         53          9

      NET_RX:    1550643    1916776

       BLOCK:          0          0

    IRQ_POLL:          0          0

     TASKLET:     333637       3930

       SCHED:     963675    2293171

     HRTIMER:          0          0

         RCU:    1542111    1590625

通过 /proc/softirqs 文件内容的变化情况,你可以发现, TIMER(定时中断)、NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU 锁)等这几个软中断都在不停变化。

其中,NET_RX,也就是网络数据包接收软中断的变化速率最快。而其他几种类型的软中断,是保证 Linux 调度、时钟和临界区保护这些正常工作所必需的,所以它们有一定的变化倒是正常的。

那么接下来,我们就从网络接收的软中断着手,继续分析。既然是网络接收的软中断,第一步应该就是观察系统的网络接收情况。这里你可能想起了很多网络工具,不过,我推荐今天的主人公工具 sar 。

sar 可以用来查看系统的网络收发情况,还有一个好处是,不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数),还可以观察网络收发的 PPS,即每秒收发的网络帧数。

我们在第一个终端中运行 sar 命令,并添加 -n DEV 参数显示网络收发的报告:

# -n DEV 表示显示网络收发的报告,间隔 1 秒输出一组数据

root@ubuntu:/home/xhong# sar -n DEV 1

Linux 4.18.0-16-generic (ubuntu)    03/14/2019  _x86_64_    (2 CPU)

03:20:02 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil

03:20:03 AM veth7734be2   9401.00  14402.00    532.44    759.48      0.00      0.00      0.00      0.06

03:20:03 AM     ens33  23260.00  14758.00   1362.89    864.73      0.00      0.00      0.00      1.12

03:20:03 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

03:20:03 AM   docker0   9779.00  14909.00    420.16    786.22      0.00      0.00      0.00      0.00

对于 sar 的输出界面,我先来简单介绍一下,从左往右依次是:

  • 第一列:表示报告的时间。
  • 第二列:IFACE 表示网卡。
  • 第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是 PPS。
  • 第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是 BPS。
  • 后面的其他参数基本接近 0,显然跟今天的问题没有直接关系,你可以先忽略掉。

我们具体来看输出的内容,你可以发现:

对网卡ens33来说,每秒接收的网络帧数比较大,达到了 23260,而发送的网络帧数则比较小,只有 14758;每秒接收的千字节数只有 1362 KB,而发送的千字节数更小,只有 864 KB。

docker0 和veth7734be2的数据基本一致,只是发送和接收相反,发送的数据较大而接收的数据较小。这是 Linux 内部网桥转发导致的,你暂且不用深究,只要知道这是系统把 ens33 收到的包转发给 Nginx 服务即可。

既然怀疑是网络接收中断的问题,我们还是重点来看 ens33 :接收的 PPS 比较大,达到 23260,而接收的 BPS 却很小,只有 1362 KB。直观来看网络帧应该都是比较小的,我们稍微计算一下,1362*1024/23260= 59 字节,说明平均每个网络帧只有 59 字节,这显然是很小的网络帧,也就是我们通常所说的小包问题。

那么,有没有办法知道这是一个什么样的网络帧,以及从哪里发过来的呢?

使用 tcpdump 抓取 ens33 上的包就可以了。我们事先已经知道, Nginx 监听在 80 端口,它所提供的 HTTP 服务是基于 TCP 协议的,所以我们可以指定 TCP 协议和 80 端口精确抓包。

接下来,我们在第一个终端中运行 tcpdump 命令,通过 -i ens33 选项指定网卡 ens33,并通过 tcp port 80 选项指定 TCP 协议的 80 端口:

# -i ens33 只抓取 ens33 网卡,-n 不解析协议名和主机名

# tcp port 80 表示只抓取 tcp 协议并且端口号为 80 的网络帧

$ tcpdump -i ens33 -n tcp port 80

02:41:42.239723 IP 172.16.109.170.58080 > 172.16.109.245.80: Flags [S], seq 1664120269, win 512, length 0

...

从 tcpdump 的输出中,你可以发现172.16.109.170.58080
> 172.16.109.245.80,表示网络帧从 172.16.109.170 的 58080 端口发送到
172.16.109.245 的 80 端口,也就是从运行 hping3 机器的 58080 端口发送网络帧,目的为 Nginx 所在机器的
80 端口。

Flags [S] 则表示这是一个 SYN 包。

再加上前面用 sar 发现的, PPS 超过 23260 的现象,现在我们可以确认,这就是从 172.16.109.170 这个地址发送过来的 SYN FLOOD 攻击。

到这里,我们已经做了全套的性能诊断和分析。从系统的软中断使用率高这个现象出发,通过观察 /proc/softirqs 文件的变化情况,判断出软中断类型是网络接收中断;再通过 sar 和 tcpdump ,确认这是一个 SYN FLOOD 问题。

SYN FLOOD 问题最简单的解决方法,就是从交换机或者硬件防火墙中封掉来源 IP,这样 SYN FLOOD 网络帧就不会发送到服务器中。

案例结束后,也不要忘了收尾,记得停止最开始启动的 Nginx 服务以及 hping3 命令。

在第一个终端中,运行下面的命令就可以停止 Nginx 了:

# 停止 Nginx 服务

$ docker rm -f nginx

然后到第二个终端中按下 Ctrl+C 就可以停止 hping3。

小结:

软中断 CPU 使用率(softirq)升高是一种很常见的性能问题。虽然软中断的类型很多,但实际生产中,我们遇到的性能瓶颈大多是网络收发类型的软中断,特别是网络接收的软中断。

在碰到这类问题时,你可以借用 sar、tcpdump 等工具,做进一步分析。

原文地址:https://www.cnblogs.com/summerxye/p/11114361.html

时间: 2024-10-29 19:06:19

linux性能评估-cpu案例操作篇的相关文章

linux性能优化cpu 磁盘IO MEM

系统优化是一项复杂.繁琐.长期的工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采集.评估.监测,而且是一个长期和持续的过程,不 是说现在优化了,测试了,以后就可以一劳永逸了,也不是说书本上的优化就适合眼下正在运行的系统,不同的系统.不同的硬件.不同的应用优化的重点也不同. 优化的方法也不同.优化的参数也不同.性能监测是系统优化过程中重要的一环,如果没有监测.不清楚性能瓶颈在哪里,怎么优化呢?所以找到性能 瓶颈是性能监测的目的,也是系统优化的关键.系统由若干子系统构成,通常修改一个子系

linux性能评估与分析工具

linux是一个开源系统,其内核负责管理系统的进程,内存,设备驱动程序,文件和网络系统, 决定着系统的性能和稳定性.由于内核源码很容易获取,任何人都可以将自己认为优秀的代码 加入到其中.linux默认提供了很多服务,如何发挥linux的最大性能,如何精简系统以便适合 当前的业务需求,这需要对内核进行重新编译优化.影响linux性能的因素有很多,从底层硬件 到上层应用,每一部分都可以有优化的地方. linux性能评估与分析工具 影响linux服务器性能的因素有很多,从底层的硬件到操作系统,从网络应

Linux性能评估命令

Linux性能评估工具 https://www.cnblogs.com/dianel/p/10085454.html Linux性能评估工具 目录 介绍 负载:uptime 查看内核的信息: dmesg 查看内存状态: free.vmstat free: 查看内存,已用内存,剩余内存.交换分区等 vmstat:显示虚拟内存状况的信息. 查看CPU: mpstat:查看每个CPU的消耗信息 top: 查看Linux任务信息 查看IO:iostat 查看网卡:sar 介绍 检测服务器当前的性能,主要

【原创】一文掌握 Linux 性能分析之 I/O 篇

本文首发于我的公众号 CloudDeveloper(ID: cloud_dev),专注于干货分享,号内有大量书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 一文掌握 Linux 性能分析之 CPU 篇 一文掌握 Linux 性能分析之内存篇 这是 Linux 性能分析系列的第三篇,前两篇分别讲了 CPU 和 内存,本篇来看 IO. IO 和 存储密切相关,存储可以概括为磁盘,内存,缓存,三者读写的性能差距非常大,磁盘读写是毫秒级的(一般 0.1-10ms),内存读

Linux性能监控——CPU,Memory,IO,Network

版权声明:本文由刘爽原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/107 来源:腾云阁 https://www.qcloud.com/community 一.CPU 1.良好状态指标 CPU利用率:User Time <= 70%,System Time <= 35%,User Time + System Time <= 70%. 上下文切换:与CPU利用率相关联,如果CPU利用率状态良好,大量的上下文切换也是

linux性能监控——CPU、Memory、IO、Network

一.CPU 1.良好状态指标 CPU利用率:User Time <= 70%,System Time <= 35%,User Time + System Time <= 70%. 上下文切换:与CPU利用率相关联,如果CPU利用率状态良好,大量的上下文切换也是可以接受的. 可运行队列:每个处理器的可运行队列<=3个线程. 2.监控工具 vmstat $ vmstat 1 procs -----------memory---------- ---swap-- -----io----

Linux使用小笔记&lt;进程操作篇&gt;

问题一: 查看哪个进程占用了哪个端口.以及杀掉进程 1.查看占用端口: sudo lsof -i :80 lsof 命令 是 list open files的意思 比如: lsof filename 显示打开指定文件的所有进程 lsof -i 用以显示符合条件的进程情况(4.6.协议.:端口. @ip ) 2. 根据PID杀掉进程: sudo kill 1000  (进程号) kill 命令 语法是 kill [信号或选项] PID(s) 使用 kill -l 查看所有的信号 比如杀掉一个进程是

Linux服务器性能评估与优化(一)

网络内容总结(感谢原创) 1.前言简介 一.影响Linux服务器性能的因素 1. 操作系统级 性能调优是找出系统瓶颈并消除这些瓶颈的过程. 很多系统管理员认为性能调优仅仅是调整一下内核的参数即可解决问题, 事实上情况并不是这样. 性能调优是实现操作系统的各个子系统之间的平衡性,这些子系统包括: ?       CPU ?       内存 ?       磁盘I/O带宽 ?       网络I/O带宽 子系统之间相互依存,任何一个子系统的负载过度都能导致其他子系统出现问题,例如: * 大量的 p

Linux服务器性能评估

一.影响Linux服务器性能的因素 1. 操作系统级 CPU 内存 磁盘I/O带宽 网络I/O带宽 2. 程序应用级 二.系统性能评估标准 影响性能因素 影响性能因素 评判标准 好 坏 糟糕 CPU user% + sys%< 70% user% + sys%= 85% user% + sys% >=90% 内存 Swap In(si)=0Swap Out(so)=0 Per CPU with 10 page/s More Swap In & Swap Out 磁盘 iowait %