Linux 性能优化(四)

CPU 高负责

#top  Tasks:  75 total,   2 running,  73 sleeping,   0 stopped,   0 zombie  %Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st  %Cpu1  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st  KiB Mem :  3881904 total,  2125680 free,   288676 used,  1467548 buff/cache  KiB Swap:        0 total,        0 free,        0 used.  3318364 avail Mem      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND      1 root      20   0  188596   3636   2416 S   0.0  0.1   0:28.13 systemd      2 root      20   0       0      0      0 S   0.0  0.0   0:00.07 kthreadd      3 root      20   0       0      0      0 S   0.0  0.0   0:00.42 ksoftirqd/0      5 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 kworker/0:0H      7 root      rt   0       0      0      0 S   0.0  0.0   0:00.93 migration/0      8 root      20   0       0      0      0 S   0.0  0.0   0:00.00 rcu_bh      9 root      20   0       0      0      0 S   0.0  0.0   0:20.58 rcu_sched

top 显示了系统总体的 CPU 和内存使用情况,以及各个进程的资源使用情况

但是top 并没有细分进程的用户态 CPU 和内核态 CPU

pidstat

用户态 CPU 使用率 (%usr);  内核态 CPU 使用率(%system);  运行虚拟机 CPU 使用率(%guest);  等待 CPU 使用率(%wait);  以及总的 CPU 使用率(%CPU)。
11:45:40 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command    11:45:41 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command  11:45:42 AM     0      2562    1.00    0.00    0.00    0.00    1.00     1  barad_agent    11:45:42 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command    11:45:43 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command    11:45:44 AM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command  11:45:45 AM     0      2760    0.00    1.00    0.00    0.00    1.00     0  pidstat    Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command  Average:        0      2562    0.20    0.00    0.00    0.00    0.20     -  barad_agent  Average:        0      2760    0.00    0.20    0.00    0.00    0.20     -  pidstat

通过 top、ps、pidstat 等工具,你能够轻松找到 CPU 使用率较高(比如 100% )的进程。接下来,占用 CPU 的到底是代码里的哪个函数呢?

只有找到它,才能更高效、更针对性地进行优化。

  1. GDB(The GNU Project Debugger), 这个功能强大的程序调试利器;但是GDB调试会导致程序中断,不适合生产环境直接调试
  2. Linux perf 神器 http://www.brendangregg.com/perf.html,个人比较喜欢这个工具

案例分析

image.png
  • 使用第一篇文章中提到的机器规格进行实验
  • 安装docker、sysstat、perf、ab 等工具,如果有兴趣可以直接去下载该环境的镜像 docker.io/feisky/php-fpm和docker.io/feisky/nginx
#docker ps  CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES  545533e3427b        feisky/php-fpm      "php-fpm -F --pid ..."   5 minutes ago       Up 5 minutes                                phpfpm  2a3f5b5586b5        feisky/nginx        "nginx -g 'daemon ..."   5 minutes ago       Up 5 minutes        0.0.0.0:10000->80/tcp   nginx
#ab -c 10 -n 100 http://192.168.0.10:10000/  Document Path:          /  Document Length:        9 bytes    Concurrency Level:      10  Time taken for tests:   7.206 seconds  Complete requests:      100  Failed requests:        0  Write errors:           0  Total transferred:      17200 bytes  HTML transferred:       900 bytes  Requests per second:    13.88 [#/sec] (mean)  Time per request:       720.583 [ms] (mean)  Time per request:       72.058 [ms] (mean, across all concurrent requests)  Transfer rate:          2.33 [Kbytes/sec] received

使用top看到CPU的使用频率

image.png

每秒的并发只有13.88个,显然不符合预期

# perf top -g -p 15773

收集perf记录到本地

在 CentOS 系统中,使用 perf 工具看不到函数名,只能看到一些 16 进制格式的函数地址。其根本原因在于

perf 找不到待分析进程依赖的库,这里可以通过指定符号路径为容器文件系统的路径

具体方法如下:

#mkdir /tmp/foo  # PID=$(docker inspect --format {{.State.Pid}} phpfpm)  # bindfs /proc/$PID/root /tmp/foo  # perf report --symfs /tmp/foo

使用perf report 分析结果如下:

# perf report --symfs /tmp/foo
image.png

注释掉这段代码后

$ cat app/index.php  <?php  // test only.  $x = 0.0001;  for ($i = 0; $i <= 1000000; $i++) {    $x += sqrt($x);  }    echo "It works!"

重新启动容器进行压测结果如下:

image.png

性能百倍增加