某個應用的CPU使用率居然達到100%,我該怎么做?(三)


某個應用的CPU使用率居然達到100%,我該怎么做?(三)

1. 引

你們好,可愛的小伙伴們_!

咱們最常用什么指標來描述系統的CPU性能呢?我想你的答案,可能不是平均負載,也不是CPU上下文切換,而是另一個更直觀的指標----> CPU使用率。

CPU使用率是單位時間內CPU使用情況的統計,以百分比的方式展示。那么,作為最常用也是最熟悉的CPU指標,你能說出CPU使用率到底是怎么算出來的嗎?再有,諸如top,ps之類的性能工具展示的%user,%nice,%system,%iowait,%steal等等,你又能弄清楚他們之間的不同嗎?

2. 什么是CPU使用率?

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

為了維護CPU時間,Linux通過事先定義的節拍率(內核中表示為HZ),觸發時間中斷,並使用全局變量Jiffies記錄了開機以來的節拍數。每發生一次時間中斷,Jiffies的值就加1。

節拍率HZ是內核的可配選項,可以設置為100,250,1000等。不同的系統可能設置不同數值,你可以通過查詢/boot/config內核選項來查看它的配置值。比如在我的系統中,節拍率設置成了1000,也就是每秒鍾觸發1000次時間中斷。

[root@localhost ~]# cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 
[root@localhost ~]# uname -r
3.10.0-957.21.3.el7.x86_64
[root@localhost ~]# grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=1000

同時,正因為節拍率HZ是內核選項,所以用戶空間程序並不能直接訪問。為了方便用戶空間程序,內核還提供了一個用戶空間節拍率USER_HZ,他總是固定為100,也就是1/100秒。這樣,用戶空間程序並不需要關心內核中HZ被設置成了多少,因為它看到的總是固定值USER_HZ。

Linux通過/proc虛擬文件系統,向用戶空間提供了系統內部狀態的信息,而/proc/stat提供的就是系統的CPU和任務統計信息。比方說,如果你只關注CPU的話,可以執行下面的命令:

# 只保留各個CPU的數據
[root@localhost ~]# cat /proc/stat | grep ^cpu
cpu  37794 3 228983 1342053 54 0 36 0 0 0
cpu0 18587 2 114774 671151 38 0 7 0 0 0
cpu1 19207 1 114209 670901 16 0 29 0 0 0

這里的輸出結果是一個表格。其中,第一列表示的是CPU編號,如cpu0,cpu1,而第一行沒有編號的cpu,表示的是所有CPU的累加。其他列則表示不同場景下CPU的累加節拍數,它的單位是USER_HZ,也就是10ms(1/100秒),所以這其實就是不同場景下的CPU時間。

當然,這里每一列的順序並不需要你背下來。但是需要盡量清楚每一列的涵義,他們都是CPU使用率相關的重要指標,我們以后會在很多其他的性能工具中看到他們。

  • user(通常縮寫為us): 代表用戶態CPU時間。(注意:它並不包括下面的nice時間,但是包括了guest時間)
  • nice(通常縮寫為ni): 代表低優先級用戶態CPU時間,也就是進程的nice值被調整為1-19之間時的CPU時間(注意:nice可取值范圍是-20到19,數值越大,優先級反而越低)
  • system(通常縮寫為sys): 代表內核態CPU時間
  • idle(通常縮寫為id): 代表空閑時間。(注意:它不包括等待I/O的時間--> iowait)
  • iowait(通常縮寫為wa): 代表等待I/O的CPU時間
  • irq(通常縮寫為hi): 代表處理硬中斷的CPU時間
  • softirq(通常縮寫為si): 代表處理軟中斷的CPU時間
  • steal(通常縮寫為st): 代表當系統運行在虛擬機中的時候,被其他虛擬機占用的CPU時間
  • guest(通常縮寫為guest): 代表通過虛擬化運行其他操作系統的時間,也就是運行虛擬機的CPU時間
  • guest_nice(通常縮寫為gnice): 代表以低優先級運行虛擬機的時間

而我們通常所說的CPU使用率,就是除了空閑時間外的其他時間占總CPU時間的百分比,用公式來表示就是:

image.png-28.1kB

根據這個公式,我們就可以從/proc/stat中的數據,很容易地計算出CPU使用率。當然,也可以用每一個場景的CPU時間,除以總的CPU時間,計算出每個場景的CPU使用率。

不過,先不要着急計算,你能說出,直接用/proc/stat的數據,算的是什么時間段的CPU使用率嗎?

看到這里,你應該想起來了,這是開機以來的節拍數累加值,所以直接算出來的,是開機以來的平均CPU使用率,一般並沒有什么參考價值。

事實上,為了計算CPU使用率,性能工具一般都會取間隔一段時間(比如3秒)的兩次值,作差后,再計算出這段時間內的平均CPU使用率,即

image.png-58.5kB

這個公式,就是我們用各種性能工具所看到的CPU使用率的實際計算方法。

因此,我們要分析CPU使用率,通過各種各樣的性能分析工具就可以。而不非得去看/proc/stat文件。不過要注意的是,性能分析工具給出的都是間隔一段時間的平均CPU使用率,所以要注意間隔時間的設置,特別是用多個工具對比分析時,你一定要保證他們用的是相同的間隔時間。

比如,對比一下top和ps這兩個工具報告的CPU使用率,默認的結果很可能不一樣,因為top默認使用3秒時間間隔,而ps使用的卻是進程的整個生命周期。

3. 怎么查看CPU使用率?

知道了CPU使用率的含義后,我們再來看看要怎么查看CPU使用率。說到查看CPU使用率的工具,我猜你第一反應肯定是top和ps。的確,top和ps是最常用的性能分析工具

  • top顯示了系統總體的CPU和內存使用情況,以及各個進程的資源使用情況。
  • ps則只顯示了每個進程的資源使用情況。

例如:top的輸出格式為:

top - 12:30:10 up  3:35,  2 users,  load average: 0.00, 0.01, 0.05
Tasks: 105 total,   1 running, 104 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.2 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7990284 total,  7626660 free,   139272 used,   224352 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used.  7581316 avail Mem 
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND               
     1 root      20   0  125432   3776   2552 S   0.0  0.0   0:01.04 systemd               
     2 root      20   0       0      0      0 S   0.0  0.0   0:00.01 kthreadd              
     3 root      20   0       0      0      0 S   0.0  0.0   0:00.02 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.02 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:00.31 rcu_sched             
    10 root       0 -20       0      0      0 S   0.0  0.0   0:00.00 lru-add-drain         
    11 root      rt   0       0      0      0 S   0.0  0.0   0:00.02 watchdog/0  

在這個輸出結果中,第三行%CPU就是系統的CPU使用率,具體每一列的含義之前都已經說過了,只是把CPU時間變成了CPU使用率。不過需要注意的是,top默認顯示的是所有CPU的平均值,這個時候你只需要按下數字1,就可以切換到每個CPU的使用率了。

繼續往下看,空白行之后是進程的實時信息,每個進程都有一個%CPU列,表示進程的CPU使用率。它是用戶態和內核態CPU使用率的總和,包括進程用戶空間使用的CPU,通過系統調用執行的內核空間CPU,以及在就緒隊列等待運行的CPU。在虛擬化環境中,它還包括了運行虛擬機占用的CPU。

所以,到這里我們可以發現,top並沒有細分進程的用戶態CPU和內核態CPU。那要怎么查看每個進程的詳細情況呢? pidstat,它正是一個專門分析每個進程CPU使用情況的工具。

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

  • 用戶態CPU使用率(%usr)
  • 內核態CPU使用率(%system)
  • 運行虛擬機CPU使用率(%guest)
  • 等待CPU使用率(%wait)
  • 總的CPU使用率(%CPU)

最后的Average部分,還計算了5組數據的平均值。

# 每隔1秒輸出一組數據,共輸出5組
[root@localhost ~]# pidstat 1 5
Linux 3.10.0-957.21.3.el7.x86_64 (localhost.localdomain)    2019年08月06日     _x86_64_   (2 CPU)
22時41分57秒   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
22時41分58秒     0     11994    0.00    1.00    0.00    0.00    1.00     0  pidstat
....
Average:   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:     0      1171    0.20    0.00    0.00    0.00    0.20     -  tuned
Average:     0     11994    0.00    0.40    0.00    0.00    0.40     -  pidstat

4. CPU使用率過高,怎么分析?

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

我猜你第一個想到的,應該是GDB(The GNU Project Debugger),這個功能強大的程序調試利器。的確,GDB在調試程序錯誤方面很強大。但是,請記住GDB並不適合在性能分析的早期應用。

為什么呢?因為GDB調試程序的過程會中斷程序運行,這在線上環境往往是不允許的。所以,GDB只適合用在性能分析的后期,當你找到了出問題的大致函數后,線下再借助它來進一步調試函數內部的問題。

那么,哪種工具適合在第一時間分析進程的CPU問題呢?我的推薦是perf。它以性能事件采樣為基礎,不僅可以分析系統的各種事件和內核性能,還可以用來分析指定應用程序的性能問題。

[root@localhost ~]# yum -y install perf

使用perf分析CPU性能問題,我來說兩種最常見的

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

[root@localhost ~]# perf top

image.png-33.5kB

第一行數據

  • Samples:采樣數
  • event:事件類型
  • Event count:事件總數量

比如這個例子中:perf總共采集了103個CPU時鍾事件,而總事件數則為13569248

另外,采樣數需要我們特別注意。如果采樣數過少(比如只有十幾個),那下面的排序和百分比就沒什么實際參考價值了

第二行數據

  • 第一列Overhead,是該符號的性能事件在所有采樣中的比例,用百分比來表示
  • 第二列Shared,是該函數或指令所在的動態共享對象(Dynamic Shared Object),如內核,進程名,動態鏈接庫名,內核模塊名等
  • 第三列Object,是動態共享對象的類型。比如[.]表示用戶空間的可執行程序,或者動態鏈接庫,而[k]則表示內核空間。
  • 最后一列Symbol是符號名,也就是函數名。當函數名未知時,用十六進制的地址來表示。

還是以上面的輸出為例,我們可以看到,占用CPU時鍾最多的是perf工具自身,不過它的比例也只有7.28%,說明系統並沒有CPU性能問題。perf top的使用你應該很清楚了把。

接着再來看第二種常見方法,也就是perf record 和 perf report。perf top雖然實時展示了系統的性能信息,但是它的缺點是並不保存數據,也就無法用於離線或者后續的分析。而perf record則提供了保存數據的功能,保存后的數據,需要你用perf report解析展示。

#利用perf record采集靜態樣本,並保存到本地
[root@localhost ~]# perf record         #按Ctrl+C 終止采樣
[ perf record: Woken up 23 times to write data ]
[ perf record: Captured and wrote 5.787 MB perf.data (121112 samples) ]
[root@localhost ~]# ls
anaconda-ks.cfg  perf.data  sysstat-12.1.5-1.x86_64.rpm
[root@localhost ~]# du -sh perf.data    #這就是采集到的樣本
5.8M    perf.data

#對本地的靜態樣本進行分析
[root@localhost ~]# perf report         #會自動打開當前目錄下的perf.data
Samples: 121K of event 'cpu-clock', Event count (approx.): 30278000000                                                                         
Overhead  Command         Shared Object        Symbol                                                                                          
  99.86%  swapper         [kernel.kallsyms]    [k] native_safe_halt
   0.03%  kworker/1:1     [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.01%  bash            [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.01%  sshd            [kernel.kallsyms]    [k] e1000_xmit_frame
   0.01%  kworker/u256:3  [kernel.kallsyms]    [k] mpt_put_msg_frame
   0.00%  swapper         [kernel.kallsyms]    [k] __do_softirq
   0.00%  sshd            [kernel.kallsyms]    [k] __memcpy
   0.00%  bash            [kernel.kallsyms]    [k] __x2apic_send_IPI_mask
   0.00%  ps              [kernel.kallsyms]    [k] __memcpy
   0.00%  migration/1     [kernel.kallsyms]    [k] migration_cpu_stop
   0.00%  ps              [kernel.kallsyms]    [k] follow_page_mask
   0.00%  ps              [kernel.kallsyms]    [k] vsnprintf
   0.00%  bash            [kernel.kallsyms]    [k] __do_page_fault
   0.00%  kworker/0:1     [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.00%  perf            [kernel.kallsyms]    [k] mem_cgroup_update_page_stat
   0.00%  ps              [kernel.kallsyms]    [k] format_decode

在實際使用中,我們還經常為perf top和perf record加上-g參數,開啟調用關系的采樣,方便我們根據調用鏈來分析性能問題。

5. 案例分析

下面,我們就以Nginx+PHP的Web服務為例,來看看當你發現CPU使用率過高的問題后,要怎么使用top等工具找出異常的進程,又要怎么利用perf找出引發性能問題的函數。

5.1 環境准備

以下案例基於Centos7.6,同樣適用其他Linux操作系統

  • 機器配置:2CPU,8GB內存
  • 預先安裝docker,sysstat,perf,ab等工具
[root@localhost ~]# cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 
[root@localhost ~]# uname -r
3.10.0-957.21.3.el7.x86_64

[root@localhost ~]# yum -y install epel-release
[root@localhost ~]# yum -y install httpd-tools sysstat perf

#安裝docker
[root@localhost ~]# yum -y install yum-utils device-mapper-persistent-data lvm2
[root@localhost ~]# curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker-ce.repo
[root@localhost ~]# yum -y install docker-ce
[root@localhost ~]# systemctl start docker
[root@localhost ~]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.

#添加國內鏡像源
[root@localhost ~]# cat /etc/docker/daemon.json
{
    "registry-mirrors":[ "https://registry.docker-cn.com" ]
}
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker

#下載兩個鏡像
[root@localhost ~]# docker pull feisky/nginx
[root@localhost ~]# docker pull feisky/php-fpm

5.2 操作說明

我們這次需要用到兩個虛擬機和一個新的工具ab。

ab : 一個常用的HTTP服務性能測試工具,這里用來模擬Nginx的客戶端。

由於Nginx和PHP配置麻煩,我們在這里使用鏡像進行模擬

image.png-73.5kB

你們可以看到,其中一台用作Web服務器,來模擬性能出現問題;
另外一台用作訪問Web服務器的客戶端,來給Web服務增加壓力請求。

接下來,我們打開兩個終端,分別SSH登陸到兩台機器上,並安裝上面提到的工具。

還是同樣的情況。下面的所有命令,都默認假設以root身份運行;

5.3 操作分析

(1)在第一台虛擬機上執行下面的命令來運行Nginx和PHP的服務

[root@LNMP ~]# hostname -I
192.168.200.201
[root@LNMP ~]# docker run --name nginx -p 10000:80 -itd feisky/nginx
[root@LNMP ~]# docker run --name phpfpm -itd --network container:nginx feisky/php-fpm

(2)然后,在第二個終端使用curl訪問http://[VM1的IP]:10000,確認Nginx已經正常啟動。你應該可以看到It works!的響應。

[root@ab ~]# hostname -I
192.168.200.222 
[root@ab ~]# curl http://192.168.200.201:10000
It works!

(3)接着,我們來測試一下,這個Nginx服務的性能。在第二個終端運行下面的ab命令

# 並發10個請求測試Nginx性能,總共測試100個請求
[root@ab ~]# ab -c 10 -n 100 http://192.168.200.201:10000/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.200.201 (be patient).....done
Server Software:        nginx/1.15.4
Server Hostname:        192.168.200.201
Server Port:            10000
Document Path:          /
Document Length:        9 bytes
Concurrency Level:      10
Time taken for tests:   6.433 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      17200 bytes
HTML transferred:       900 bytes
Requests per second:    15.54 [#/sec] (mean)        # Nginx每秒平均處理的請求數
Time per request:       643.333 [ms] (mean)         # Nginx處理每個請求平均花費時間
Time per request:       64.333 [ms] (mean, across all concurrent requests)
Transfer rate:          2.61 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.3      1       1
Processing:   114  612 136.3    620     887
Waiting:      114  612 136.4    620     887
Total:        115  613 136.4    621     888
Percentage of the requests served within a certain time (ms)
  50%    621
  66%    663
  75%    684
  80%    712
  90%    767
  95%    818
  98%    849
  99%    888
 100%    888 (longest request)

從ab的輸出結果我們可以看到,Nginx能承受的每秒平均請求數只有15.54個。同學們一定會覺得,這也太差了吧。

那么到底是哪里出了問題呢?我們用top和pidstat再來觀察下。

這次,我們在第二個終端,將測試的請求數量增加到10000。這樣當你在第一個終端使用性能分析工具時,Nginx的壓力還是繼續的。

(4)繼續在第二個終端,運行ab命令:

[root@ab ~]# ab -c 10 -n 10000 http://192.168.200.201:10000/

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

image.png-56.1kB

在這里可以看到,系統中有幾個php-fpm進程的CPU使用率加起來接近200%;
而每個CPU的用戶使用率(us)也已經超過了98%,接近飽和。這樣,我們就可以確認,正是用戶空間的php-fpm進程,導致CPU使用率驟升。

那么,我們繼續進行實驗,我們該如何知道是php-fpm的哪個函數導致了CPU使用率升高呢?我們用perf分析一下。

(5)在第一個終端運行下面的perf命令:

# -g 開啟調用關系分析,-p指定php-fpm的進程號14372
[root@LNMP ~]# perf top -g -p 14372

我們可以通過鍵盤上下左右進行移動,移動到php-fpm進程時,利用Enter進行進程的打開操作

image.png-43.4kB

通過perf進行分析,我們發現分析出來的都是內存的地址,具體函數的名字無法識別

這是因為,我們的Web服務器是在容器里的,容器完全封裝了軟件的運行環境,其中也包含了所需的依賴庫函數等

因此,我們在宿主機操作系統上分析,是無法找到對應的容器的依賴函數庫的(函數庫在容器里,不在操作系統上)

所以,我們需要通過perf record -g -p采集分析報告

而后,將分析報告perf.data復制到容器里后,通過容器里的perf命令進行分析才可以。

(6)生成perf分析報告,復制報告到容器內,進行分析

#生成perf分析報告
[root@LNMP ~]# perf record -g -p 14372
[ perf record: Woken up 17 times to write data ]
[ perf record: Captured and wrote 4.038 MB perf.data (34532 samples) ]
[root@LNMP ~]# ls
anaconda-ks.cfg  perf.data
[root@LNMP ~]# du -sh perf.data
4.1M    perf.data

#將分析報告拷貝到php-fpm容器中的/tmp目錄下
[root@LNMP ~]# docker cp perf.data phpfpm:/tmp

#進行phpfpm容器中
[root@LNMP ~]# docker exec -it phpfpm /bin/bash
root@4ae3d2daa8b8:/app# cd /tmp

#安裝perf分析工具(此為Ubentu系統)
root@4ae3d2daa8b8:/tmp# apt-get update && apt-get -y install linux-perf linux-tools procps

#對perf.data進行分析
root@4ae3d2daa8b8:/tmp# perf_4.9 report

image.png-68.1kB

image.png-41.5kB

這次通過在容器內的分析,我們發現php-fpm進程一直都在反復調用兩個函數名:add_function和sqrt

(7)add_function和sqrt是什么函數代碼

# 將php-fpm容器的網頁代碼拷貝到宿主機上進行分析
[root@LNMP yunjisuan]# pwd
/root/yunjisuan
[root@LNMP yunjisuan]# ls
[root@LNMP yunjisuan]# docker cp phpfpm:/app .
[root@LNMP yunjisuan]# ls
app
[root@LNMP yunjisuan]# grep -r “sqrt” app/
app/index.php:  $x += sqrt($x);             #找到了有關sqrt函數的調用,在app目錄下的index.php文件里
[root@LNMP yunjisuan]# grep -r "add_function" app/  #這個函數調用沒找到,因為這其實是個PHP的內置調用函數

OK,原來只有sqrt函數在app/index.php文件中調用了。那最后一步,我們就該看看這個文件的源代碼了。

[root@LNMP yunjisuan]# cat app/index.php 
<?php
// test only.
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
  $x += sqrt($x);
}

echo "It works!"

到此應該已經發現,這其實就是一個PHP的測試頁代碼。

而之所以會出現這個問題,只是因為在發布應用代碼的時候,沒有刪除PHP的測試頁代碼

因此,我們刪除測試頁內容再重新啟動容器即可

(8)修復Web服務器的測試頁問題

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
9867f918a31c        feisky/php-fpm      "php-fpm -F --pid /o…"   5 seconds ago       Up 4 seconds                                phpfpm
41db97b9c815        feisky/nginx        "nginx -g 'daemon of…"   31 seconds ago      Up 31 seconds       0.0.0.0:10000->80/tcp   nginx

#進入nginx容器
[root@localhost ~]# docker exec -it nginx /bin/bash
root@41db97b9c815:/# cd app/
root@41db97b9c815:/app# ls
404.html  index.php  ok.php  phpinfo.php
root@41db97b9c815:/app# cat index.php   #錯誤的測試頁
<?php
// test only.
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
  $x += sqrt($x);
}
echo "It works!"
?>root@41db97b9c815:/app# cat ok.php    #正常頁
<?php
echo "It works!"
?>
root@41db97b9c815:/app# cat ok.php > index.php    #用正常頁內容覆蓋測試頁內容
#退出nginx容器
root@41db97b9c815:/app# exit
exit

#進入phpfpm容器,修改測試頁
[root@localhost ~]# docker exec -it phpfpm /bin/bash
root@41db97b9c815:/app# ls
404.html  index.php  ok.php  phpinfo.php
root@41db97b9c815:/app# cat ok.php > index.php 
root@41db97b9c815:/app# exit
exit

#重新啟動nginx和phpfpm容器
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
9867f918a31c        feisky/php-fpm      "php-fpm -F --pid /o…"   2 minutes ago       Up 2 minutes                                phpfpm
41db97b9c815        feisky/nginx        "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        0.0.0.0:10000->80/tcp   nginx
[root@localhost ~]# docker restart nginx phpfpm
nginx
phpfpm

(9)再次對Web服務的虛擬機進行壓力測試

[root@ab ~]# ab -c 10 -n 10000 http://192.168.200.201:10000/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.200.201 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:        nginx/1.15.4
Server Hostname:        192.168.200.201
Server Port:            10000
Document Path:          /
Document Length:        9 bytes
Concurrency Level:      10
Time taken for tests:   2.255 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      1720000 bytes
HTML transferred:       90000 bytes
Requests per second:    4434.83 [#/sec] (mean)      #nginx每秒處理的請求數提高到4434個
Time per request:       2.255 [ms] (mean)
Time per request:       0.225 [ms] (mean, across all concurrent requests)
Transfer rate:          744.91 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     1    2   0.8      2       9
Waiting:        1    2   0.7      2       9
Total:          1    2   0.8      2       9
Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      3
  90%      3
  95%      4
  98%      4
  99%      5
 100%      9 (longest request)

6. 階段小結

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

  • 用戶CPU和Nice CPU高,說明用戶態進程占用了較多的CPU,所以應該着重排查進程的性能問題。
  • 系統CPU高,說明內核態占用了較多的CPU,所以應該着重排查內核線程或者系統調用的性能問題
  • I/O等待CPU高,說明等待I/O的時間比較長,所以應該着重排查系統存儲是不是出現了I/O問題。
  • 軟中斷和硬中斷高,說明軟中斷或硬中斷的處理程序占用了較多的CPU,所以應該着重排查內核中的中斷服務程序。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM