1. 程式人生 > >關於linux系統CPU篇--->CPU使用率升高

關於linux系統CPU篇--->CPU使用率升高

可執行 enc unlock nic pidstat inf 指令 終端 關系

1.CPU使用率為單位時間內CPU使用情況的統計,以百分比的方式展示。

LINUX作為一個多任務操作系統,將每個CPU的時間劃分為很短的時間片,再通過調度器輪流分配給各個任務使用,因此造成多任務同時運行的錯覺

2.如何查看CPU使用率?

TOP和PS是最常用的性能分析工具。TOP顯示了系統總體的CPU和內存使用情況,以及各個進程的資源使用情況

PS則只顯示了每個進程的資源使用情況

pidstat是專門分析每個進程的CPU使用情況的工具

TOP輸出:

# 默認每 3 秒刷新一次
$ top
top - 11:58:59 up 9 days, 22:47, 1 user, load average: 0.03, 0.02, 0.00

Tasks: 123 total, 1 running, 72 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8169348 total, 5606884 free, 334640 used, 2227824 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 7497908 avail Mem

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

1 root 20 0 78088 9288 6696 S 0.0 0.1 0:16.83 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.05 kthreadd
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H

TOP默認顯示的是所有CPU的平均值,這時候按下1,就可以切換到每個CPU的使用率了

下面的pidstat命令,就間隔1秒,展示了進程的5組CPU使用率,包括:

%usr用戶態CPU使用率

%system 系統CPU使用率

%guest 運行虛擬機CPU使用率

%wait 等待IO CPU使用率

%cpu 總的CPU使用率

最後的average部分,還計算了5組數據的平均值

pidstat輸出:

# 每隔 1 秒輸出一組數據,共輸出 5 組
$ pidstat 1 5
15:56:02 UID PID %usr %system %guest %wait %CPU CPU Command
15:56:03 0 15006 0.00 0.99 0.00 0.00 0.99 1 dockerd

...

Average: UID PID %usr %system %guest %wait %CPU CPU Command
Average: 0 15006 0.00 0.99 0.00 0.00 0.99 - dockerd

3.CPU使用率過高怎麽辦?

使用top,ps,pidstat等工具,能夠輕松找到占用CPU使用率較高(100%)的進程,接下來,你可能想知道占用CPU的是哪個函數呢,找到它,才能更有效,更針對性的進行性能優化。

那麽那種工具最適合在第一時間分析進程的CPU問題呢,推薦的是perf。perf是linux2.6.31以後內置的性能分析工具,包含了perf top ,perf record,perf report

第一種:perf top,類似於top,它能夠實時顯示占用CPU時鐘最多的函數或者指令,因此可以用來查找熱點函數,使用界面如下:

$ perf top
Samples: 833 of event ‘cpu-clock‘, Event count (approx.): 97742399
Overhead Shared Object Symbol
7.28% perf [.] 0x00000000001f78a4
4.72% [kernel] [k] vsnprintf
4.32% [kernel] [k] module_get_kallsym
3.65% [kernel] [k] _raw_spin_unlock_irqrestore
...

輸出結果中,第一行包含三個數據,分別是采樣數,事件類型和事件總數量,輸出中可以看到perf采集了833個CPU時鐘事件,而總事件數則為97742399

如果輸出結果中,采樣數(Samples)只有10幾個,那下面的排序和百分比就沒什麽實際參考價值

Overhead:該符號的性能事件,在所有采樣中的比例,用百分比來展示

Shared:該函數或指令所在的動態共享對象(Dynamic Shared Object),如內核,進程名,動態連接庫名,內核模塊名等

Object:動態共享對象的類型。比如[.]表示用戶空間的可執行程序,或者動態鏈接庫,而[k]則表示內核空間

Symbol:是符號名,也就是函數名。當函數名未知時,用十六進制地址表示

從上面的輸出中可以看到,占用CPU最多的是perf工具自身,不過它的比例也只有7.28%,說明系統並沒有CPU性能問題。

第二種常見用法:也就是perf record和perf report

perf record 提供了保存數據的功能,保存後的數據,可以用perf report 解析展示

4.案例分析:

(1).使用兩臺linux虛擬機,其中一臺用作web服務器,模擬性能問題。需要安裝docker,nginx,perf,sysstat等工具

另外一臺用作客戶端,需要安裝ab,curl

(2).在第一臺虛擬機中執行下面命令運行nginx和php應用:

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

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

(3).在第二臺虛擬機(客戶端)執行curl 命令,確認nginx已經正常啟動:

# 192.168.0.10 是第一臺虛擬機的 IP 地址

$ curl http://192.168.0.10:10000/

It works!

(4).測試nginx服務的性能:

# 並發 10 個請求測試 Nginx 性能,總共測試 100 個請求
$ ab -c 10 -n 100 http://192.168.0.10:10000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd,
...
Requests per second: 11.63 [#/sec] (mean)
Time per request: 859.942 [ms] (mean)
...

從ab的結果輸出中,發現nginx能承受的每秒平均請求數只有11.63.性能比較差

(5)繼續執行ab,將請求數增加到10000,這樣在第一個終端使用性能分析工具時,nginx壓力還是繼續

ab -c 10 -n 10000 http://192.168.0.10:10000/

(6).回到第一個終端運行top命令,並按下數字1,切換到每個CPU的使用率:

$ top
...
%Cpu0 : 98.7 us, 1.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 99.3 us, 0.7 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21514 daemon 20 0 336696 16384 8712 R 41.9 0.2 0:06.00 php-fpm
21513 daemon 20 0 336696 13244 5572 R 40.2 0.2 0:06.08 php-fpm
21515 daemon 20 0 336696 16384 8712 R 40.2 0.2 0:05.67 php-fpm
21512 daemon 20 0 336696 13244 5572 R 39.9 0.2 0:05.87 php-fpm
21516 daemon 20 0 336696 16384 8712 R 35.9 0.2 0:05.61 php-fpm

發現占用CPU最多的是PHP-fpm進程

(7).怎麽知道是php-fpm的那個函數導致了CPU使用率升高呢,我們來用perf分析一下。在第一個終端運行下面的perf命令

# -g 開啟調用關系分析,-p 指定 php-fpm 的進程號 21515
$ perf top -g -p 21515

(8).按方向鍵切換到php-fpm,再按下會車鍵展開php-fpm的調用關下,發現調用關系最終到了sqrt和add_function

技術分享圖片

(9).拷貝出nginx應用的源碼,看看是不是調用了這兩個函數:

# 從容器 phpfpm 中將 PHP 源碼拷貝出來
$ docker cp phpfpm:/app .

# 使用 grep 查找函數調用
$ grep sqrt -r app/ # 找到了 sqrt 調用
app/index.php: $x += sqrt($x);
$ grep add_function -r app/ # 沒找到 add_function 調用,這其實是 PHP 內置函數

原來只有sqrt函數在ap/idex.php文件中調用了。看看這個文件的源碼:

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

echo "It works!"

發現原來是測試代碼沒刪就直接發布應用了。

(10).優化:

# 停止原來的應用
$ docker rm -f nginx phpfpm
# 運行優化後的應用
$ docker run --name nginx -p 10000:80 -itd feisky/nginx:cpu-fix
$ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:cpu-fix

(11).重新在第二臺虛擬機中測試nginx性能:

$ ab -c 10 -n 10000 http://10.240.0.5:10000/
...
Complete requests: 10000
Failed requests: 0
Total transferred: 1720000 bytes
HTML transferred: 90000 bytes
Requests per second: 2237.04 [#/sec] (mean)
Time per request: 4.470 [ms] (mean)
Time per request: 0.447 [ms] (mean, across all concurrent requests)
Transfer rate: 375.75 [Kbytes/sec] received
...

從這裏可以發現,現在每秒的請求數,已經從原來的11變成了2237

總結:

CPU使用率是最直觀和最常用的系統性能指標,更是我們在排查系統性能問題時。通常會關註的第一個指標。所以我們要熟悉它的含義,尤其要弄清楚用戶(user%)、NIce(%nice)、系統(%system),等待IO(%iowait),中斷(%irq),軟中斷(%softirq)

這幾種不同的CPU使用率。

(1).用戶和Nice CPU高,說明用戶進程占用了較多的CPU,所以應該著重排查進程的性能問題

(2).系統CPU高,說明內核態占用了較多的CPU,所以應該著重排查內核線程或系統調用的性能問題

(3).IO等待CPU高,說明等待IO的時間比較長,應該著重排查系統存儲是不是出現了IO問題

(4).軟中斷和硬中斷高,說明軟中斷或硬中斷處理程序占用了較多的CPU,所以應該著重排查內核中的中斷服務程序

碰到CPU使用率升高的問題,可以借助TOP,pidstat等工具,確認引發CPU性能問題的來源,再使用perf等工具,排查出引起性能問題的具體函數

關於linux系統CPU篇--->CPU使用率升高