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

性能百倍增加