學(xué)習(xí)筆記-Linux性能優(yōu)化-CPU

平均負(fù)載

1. 理解平均負(fù)載

??平均負(fù)載對(duì)很多人來(lái)說(shuō)既熟悉又陌生,那我們?nèi)绾卫斫夂陀^測(cè)這個(gè)最常見(jiàn)、也是最重要的系統(tǒng)指標(biāo)呢?
??平均負(fù)載是指單位時(shí)間內(nèi),系統(tǒng)處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù)量,也就是平均活躍進(jìn)程數(shù)。

??可運(yùn)行狀態(tài):指正在使用或者正在等待 CPU 的進(jìn)程,也就是我們常用 ps 命令看到的,處于 R 狀態(tài)(Running 或 Runnable)的進(jìn)程。
??不可中斷狀態(tài):指的是正處于內(nèi)核態(tài)關(guān)鍵流程中的進(jìn)程,并且這些流程是不可打斷的,比如最常見(jiàn)的是等待硬件設(shè)備的 I/O 響應(yīng),也就是我們?cè)?ps 命令中看到的 D 狀態(tài)(Uninterruptible Sleep,也稱為 Disk Sleep)的進(jìn)程。不可中斷狀態(tài)實(shí)際上是系統(tǒng)對(duì)進(jìn)程和硬件設(shè)備的一種保護(hù)機(jī)制,比如當(dāng)一個(gè)進(jìn)程向磁盤寫入數(shù)據(jù)時(shí),在得到磁盤回復(fù)之前,它是不能被其他進(jìn)程或者中斷打斷的,此時(shí)進(jìn)程就處于不可中斷狀態(tài),否則會(huì)處于磁盤數(shù)據(jù)和進(jìn)程數(shù)據(jù)不一致的情況。

??因此,你可以簡(jiǎn)單的將平均負(fù)載理解為平均活躍進(jìn)程數(shù)量,那么最理想的狀態(tài),就是每個(gè)CPU上剛好運(yùn)行一個(gè)進(jìn)程,這樣每個(gè)CPU都得到了充分利用。在實(shí)際的情況中,平均負(fù)載為多少時(shí)合理呢?多大說(shuō)明系統(tǒng)負(fù)載高?多小說(shuō)明負(fù)載很低呢?
??一般情況下,當(dāng)平均負(fù)載高于CPU數(shù)量的70%的時(shí)候,你就應(yīng)該分析排查負(fù)載高的問(wèn)題了,一旦負(fù)載變高,就可能導(dǎo)致進(jìn)程響應(yīng)變慢,進(jìn)而影響正常的功能,當(dāng)然這個(gè)數(shù)字并不是絕對(duì)的,最推薦的方式,還是監(jiān)控系統(tǒng)的平均負(fù)載,然后根據(jù)更多的歷史數(shù)據(jù),判斷負(fù)載的變化趨勢(shì),當(dāng)發(fā)現(xiàn)負(fù)載有明顯的升高趨勢(shì)時(shí),再去分析和調(diào)查。
??現(xiàn)實(shí)工作中,我們會(huì)把平均負(fù)載CPU使用率混淆,讓我們重新回顧一下平均負(fù)載的概念:平均負(fù)載是指單位時(shí)間內(nèi),系統(tǒng)處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù)量。也就是說(shuō)它不僅包含正在使用CPU的進(jìn)程,還包括等待CPU和等待IO的進(jìn)程。而CPU使用率表示單位時(shí)間內(nèi),非空閑狀態(tài)所占的比例,比如:

  • CPU密集型,使用大量的CPU會(huì)使得平均負(fù)載升高。
  • IO密集型,等待IO也會(huì)導(dǎo)致平均負(fù)載升高,但是此時(shí)CPU使用率不一定高。
  • 大量等待CPU進(jìn)程調(diào)度也會(huì)導(dǎo)致平均負(fù)載升高,此時(shí)的CPU使用率也會(huì)比較高。

2. 平均負(fù)載分析

在分析平均負(fù)載之前,先簡(jiǎn)單的介紹一下 sysstat,它包含了常用的Linux 性能工具,用來(lái)監(jiān)控和分析系統(tǒng)的性能,我們會(huì)用到其中的 mpstatpidstat。

?? mpstat 是一個(gè)常用的 CPU 性能分析工具,用來(lái)實(shí)時(shí)查看每個(gè) CPU的性能指標(biāo), 以及所有CPU 的平均指標(biāo)。
??pistat是一個(gè)常用的進(jìn)程性能分析工具,用來(lái)實(shí)時(shí)查看進(jìn)程的CPU、內(nèi)存、IO以及上下文切換等性能指標(biāo)。

??在分析平均負(fù)載之前,我們可以通過(guò) lscpu 命令查看當(dāng)前機(jī)器的CPU信息。

$ lscpu
CPU(s):  1
...
1. 場(chǎng)景一: CPU密集進(jìn)程
  1. 通過(guò) uptime 命令查看平均負(fù)載的變化情況(過(guò)去 1 分鐘、5 分鐘、15 分鐘),由下圖終端的結(jié)果來(lái)看,平均負(fù)載時(shí)逐步增高的。
$ watch -d uptime
..., load average: 1.00, 0.75, 0.39
  1. 通過(guò) mpstat 查看CPU使用率的變化情況,由下圖執(zhí)行結(jié)果來(lái)看,有個(gè)線程的CPU 占用率為 100%, 但是 iowait 只有 0 ,說(shuō)明平均負(fù)載的升高是因?yàn)?code>CPU 的利用率較高。
$ mpstat -P ALL 5 1
08:42:30 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
08:42:35 PM  all    0.50    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   0.00
08:42:35 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   0.00
08:42:35 PM    1    100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  0.00
  1. 通過(guò) pidstat 查看進(jìn)程的性能指標(biāo)如下,我們可以看到到底為哪個(gè)進(jìn)程導(dǎo)致CPU利用率升高。
$ pidstat -u 5 1

08:51:25 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command
08:51:31 PM  1002      1024    100.00   0.00    0.00    100.00     1  ***
分析步驟總結(jié)
  1. 確定服務(wù)器的核心數(shù)量,通過(guò) uptime 命令觀察平均負(fù)載的趨勢(shì)走向。
  2. 通過(guò) mpstat 命令服務(wù)器的運(yùn)行情況, 包括 cpu 利用率、io 等待、用戶態(tài)、系統(tǒng)態(tài)、爭(zhēng)用CPU所占時(shí)間 等各個(gè)指標(biāo)所占比例等等。
  3. 通過(guò) pidstat 命令查看哪個(gè)進(jìn)程所占的 cpu或者 iowait 高,又或者是系統(tǒng)運(yùn)行進(jìn)程超出了cpu 的運(yùn)行能力, 導(dǎo)致 cpu過(guò)載。

CPU上下文切換

??Linux 是一個(gè)多任務(wù)操作系統(tǒng),它支持遠(yuǎn)大于 CPU 數(shù)量的任務(wù)同時(shí)運(yùn)行。當(dāng)然,這些任務(wù)實(shí)際上并不是真的在同時(shí)運(yùn)行,而是因?yàn)橄到y(tǒng)在很短的時(shí)間內(nèi),將 CPU 輪流分配給它們,而每個(gè)人任務(wù)執(zhí)行之前,CPU都必需知道該任務(wù)所需的數(shù)據(jù)從哪里加載,又從哪里開(kāi)始運(yùn)行(CPU寄存器和程序計(jì)數(shù)器)。CPU上下文切換實(shí)際上就是把前一個(gè)任務(wù)的上下文保存起來(lái),然后加載當(dāng)前正在準(zhǔn)備執(zhí)行的任務(wù)的上下文到寄存器和計(jì)數(shù)器中,運(yùn)行新任務(wù)。
??實(shí)際CPU的上下文切換可以分為幾個(gè)不同的場(chǎng)景,進(jìn)程上下文切換、線程上下文切換以及中斷上下文切換

進(jìn)程上下文切換

?? Linux 特權(quán)等級(jí),將進(jìn)程的運(yùn)行空間分為內(nèi)核空間和用戶空間,內(nèi)核空間具有最高的訪問(wèn)權(quán)限;而用戶空間只能訪問(wèn)受限的資源,不能直接訪問(wèn)內(nèi)存等硬件設(shè)備,必需通過(guò)系統(tǒng)調(diào)用陷入內(nèi)核中,才能訪問(wèn)這些特權(quán)資源。從用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)變,是通過(guò)系統(tǒng)調(diào)用完成的。比如我們的程序訪問(wèn)文件內(nèi)容就需要進(jìn)行系統(tǒng)調(diào)用,首先通過(guò)系統(tǒng)調(diào)用打開(kāi)文件,將內(nèi)容讀取到內(nèi)核空間,拷貝到用戶空間之后才能被程序處理。
??由此可見(jiàn),系統(tǒng)調(diào)用的時(shí)候會(huì)發(fā)生了CPU上下文切換。 CPU寄存器里原來(lái)用戶態(tài)程序的上下文信息需要先保存起來(lái),為了執(zhí)行內(nèi)核態(tài)代碼,加載內(nèi)核代碼的上下文,運(yùn)行內(nèi)核任務(wù),系統(tǒng)調(diào)用結(jié)束之后,需要切換到用戶空間。所以,一次系統(tǒng)調(diào)用,會(huì)發(fā)生兩次CPU上下文切換。
??系統(tǒng)調(diào)用過(guò)程中,并不會(huì)涉及到虛擬內(nèi)存等進(jìn)程用戶態(tài)的資源,也不會(huì)切換進(jìn)程。這跟我們通常所說(shuō)的進(jìn)程上下文切換是不一樣的,進(jìn)程上下文切換指的是從一個(gè)進(jìn)程切換到另一個(gè)進(jìn)程,而系統(tǒng)調(diào)用一直是一個(gè)進(jìn)程,所以通常被稱為特權(quán)模式切換,而不是上下文切換。
??進(jìn)程是由內(nèi)核來(lái)管理和調(diào)度的,進(jìn)程的切換只能發(fā)生在內(nèi)核態(tài)。所以,進(jìn)程的上下文不僅包括了虛擬內(nèi)存、棧、全局變量等用戶空間的資源,還包括了內(nèi)核堆棧、寄存器等內(nèi)核空間的狀態(tài)。因此進(jìn)程上下文切換比系統(tǒng)調(diào)用多了一步,保存當(dāng)前進(jìn)程的內(nèi)核狀態(tài)和CPU寄存器之前,需要先把該進(jìn)程的虛擬內(nèi)存、棧等保存起來(lái)。
究竟什么時(shí)候會(huì)切換進(jìn)程上下文呢?

  • 操作系統(tǒng)為了保證公平調(diào)度,CPU時(shí)間被劃分為一段段的時(shí)間片,然后輪流分配給各個(gè)進(jìn)程,當(dāng)某個(gè)進(jìn)程的時(shí)間片耗盡之后,會(huì)被系統(tǒng)掛起,切換到其他等待CPU的進(jìn)程運(yùn)行。
  • 進(jìn)程在資源不足的情況下,要等到資源滿足之后才可以運(yùn)行,這個(gè)時(shí)候也會(huì)被掛起,由系統(tǒng)調(diào)度其他進(jìn)程。
  • 進(jìn)程通過(guò)sleep 函數(shù)將自己主動(dòng)掛起。
  • 優(yōu)先級(jí)較高的進(jìn)程運(yùn)行時(shí),為了保證高優(yōu)先級(jí)的先被運(yùn)行,當(dāng)前進(jìn)程會(huì)被掛起。
  • 發(fā)生硬件中斷時(shí),CPU進(jìn)程會(huì)中斷掛起,轉(zhuǎn)而執(zhí)行內(nèi)核中的中斷服務(wù)進(jìn)程。
線程上下文切換

??線程是調(diào)度的基本單位,而進(jìn)程則是資源擁有的基本單位。內(nèi)核中的任務(wù)調(diào)度,實(shí)際調(diào)度的對(duì)象時(shí)線程,而進(jìn)程只是給線程提供了虛擬內(nèi)存、全局變量等資源。

  • 當(dāng)進(jìn)程只有一個(gè)線程時(shí),進(jìn)程等于線程。
  • 當(dāng)進(jìn)程有多個(gè)線程時(shí),全局變量等線程公共資源是不用修改的,而線程自己的私有數(shù)據(jù),比如棧和寄存器,也是需要保存的。
    ??如果為第一種,線程上下文切換過(guò)程和進(jìn)程切換相同,對(duì)于第二種,由于不需要保存公共資源,所以同進(jìn)程內(nèi)的線程切換,要比多進(jìn)程間的切換消耗更小。
中斷上下文切換

??為了快速響應(yīng)硬件的事件,中斷處理會(huì)打斷進(jìn)程的正常調(diào)度和執(zhí)行,轉(zhuǎn)而調(diào)用中斷處理程序,響應(yīng)設(shè)備事件,而在打斷進(jìn)程的正常調(diào)度之前,需要保存當(dāng)前進(jìn)程的狀態(tài)。跟進(jìn)程上下文不同,中斷并不涉及進(jìn)程的用戶態(tài),所以不需要保存和恢復(fù)這個(gè)進(jìn)程的虛擬內(nèi)存、全局變量等用戶態(tài)資源。中斷上下文,其實(shí)只包括內(nèi)核態(tài)中斷服務(wù)程序執(zhí)行所必需的狀態(tài),包括 CPU 寄存器、內(nèi)核堆棧、硬件中斷參數(shù)等。
??對(duì)同一個(gè) CPU 來(lái)說(shuō),中斷處理比進(jìn)程擁有更高的優(yōu)先級(jí),所以中斷上下文切換并不會(huì)與進(jìn)程上下文切換同時(shí)發(fā)生。由于中斷會(huì)打斷正常進(jìn)程的調(diào)度和執(zhí)行,所以大部分中斷處理程序都短小精悍,以便盡可能快的執(zhí)行結(jié)束,但是中斷上下文切換也需要消耗 CPU,切換次數(shù)過(guò)多也會(huì)耗費(fèi)大量的 CPU,甚至嚴(yán)重降低系統(tǒng)的整體性能。所以,當(dāng)你發(fā)現(xiàn)中斷次數(shù)過(guò)多時(shí),就需要注意去排查它是否會(huì)給你的系統(tǒng)帶來(lái)嚴(yán)重的性能問(wèn)題。

查看上下文切換情況

??過(guò)多的上下文切換,會(huì)將資源耗費(fèi)在寄存器、內(nèi)核棧以及虛擬內(nèi)存的數(shù)據(jù)的保存和恢復(fù)上,縮短進(jìn)程真正的執(zhí)行時(shí)間,而上下文的切換包括兩種:

  • 自愿上下文切換:指進(jìn)程無(wú)法獲取所需要的資源,導(dǎo)致的上下文切換,比如IO、內(nèi)存等系統(tǒng)資源不足。
  • 非自愿上下文切換:指的是進(jìn)程的時(shí)間片已經(jīng)到期,被系統(tǒng)強(qiáng)制調(diào)度發(fā)生。
    ??我們主要通過(guò)vmstat 查詢系統(tǒng)的上下文切換情況, 主要特別關(guān)注以下四列內(nèi)容:
  1. r: 就緒隊(duì)列的長(zhǎng)度,表示運(yùn)行或者等待CPU的進(jìn)程數(shù)量。
  2. b:表示不可中斷睡眠狀態(tài)的進(jìn)程數(shù)。
  3. in:每秒中斷次數(shù)。
  4. cs: 每秒上下文切換的次數(shù)。
場(chǎng)景: 案例分析
  1. 首先通過(guò) vmstat 工具 觀察系統(tǒng)的上下文切換情況:
$ 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
11  0      0 323460 140952 1159544    0    0     2     8   74   65  1  1 99  0  0
 9  0      0 323460 140952 1159544    0    0     0     0 1550 942091 39 61  0  0  0

??關(guān)注內(nèi)容:上下文切換次數(shù):由 65 升高為 942091;有序隊(duì)列的長(zhǎng)度 8 已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了系統(tǒng)的CPU個(gè)數(shù)(2);CPU使用率(us + sy)已經(jīng)到達(dá)了 100%;中斷次數(shù)也提升到了 1550 次。
綜合這些指標(biāo)我們可以知道系統(tǒng)的就緒隊(duì)列過(guò)長(zhǎng),導(dǎo)致大量的上下文切換,而上下文切換又導(dǎo)致了CPU 占用率的升高。

  1. 通過(guò) pidstat 查看CPU和進(jìn)程上下文切換情況:
$ pidstat -w -u 1

02:22:06 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
02:22:07 PM     0      1058    1.00    0.00    0.00    0.00    1.00     0  AliYunDun
02:22:07 PM     0     17861   38.00   61.00    0.00    0.00   99.00     0  sysbench

02:22:06 PM   UID       PID   cswch/s nvcswch/s  Command
02:22:07 PM     0        11      1.00      0.00  ksoftirqd/0
02:22:07 PM     0        12     42.00      0.00  rcu_sched
02:22:07 PM     0        22      2.00      0.00  kcompactd0
02:22:07 PM     0       145      5.00      0.00  load_calc
02:22:07 PM    32       498      1.00      0.00  rpcbind
02:22:07 PM  1003       569      1.00      0.00  memcached
02:22:07 PM     0       732      1.00      0.00  php-fpm
02:22:07 PM  1002       790     10.00      0.00  redis-server
02:22:07 PM     0      1058     11.00      0.00  AliYunDun
02:22:07 PM     0      1120     31.00      0.00  AliYunDunMonito
02:22:07 PM     0      5201     10.00      0.00  AliSecGuard
02:22:07 PM     0     17678      1.00      0.00  sshd
02:22:07 PM     0     17857      1.00      0.00  kworker/u4:1-events_unbound
02:22:07 PM     0     17860      6.00      0.00  kworker/0:1-events
02:22:07 PM     0     17890      1.00      0.00  pidstat

從輸出發(fā)現(xiàn),CPU使用率的升高是因?yàn)?sysbench導(dǎo)致的,但是上下文切換是來(lái)自其他的進(jìn)程,不過(guò)圖中輸出的上下文切換次數(shù),明顯比 942091 小的多,講到的幾種上下文切換場(chǎng)景。其中提到, Linux 調(diào)度的基本單位實(shí)際上是線程,那么,是不是 pidstat 忽略了線程的數(shù)據(jù)呢?通過(guò) man pidstat 的描述,實(shí)際上默認(rèn)展示的是進(jìn)程數(shù)據(jù),所以我們需要再加上 -t 參數(shù):

$ pidstat -wt 1

02:30:37 PM   UID      TGID       TID   cswch/s nvcswch/s  Command
02:30:39 PM     0         -     17944  12110.71  74812.50  |__sysbench
02:30:39 PM     0         -     17945  13327.68  71582.14  |__sysbench
02:30:39 PM     0         -     17946  10166.96  76762.50  |__sysbench
02:30:39 PM     0         -     17947   5872.32  88392.86  |__sysbench
02:30:39 PM     0         -     17948  14217.86  68983.93  |__sysbench
……

??雖然 sysbench 進(jìn)程的上下文切換次數(shù)不多,但是它的子進(jìn)程的上下文次數(shù)卻又很多,所以罪魁禍?zhǔn)拙褪沁^(guò)多的 sysbench 線程。那四個(gè)關(guān)注指標(biāo)中的中斷次數(shù)又如何解釋呢?到底是什么類型的中斷上升了呢?
我們可以通過(guò) /proc/interrupts 這個(gè)只讀文件中讀取中斷發(fā)生的類型,通過(guò)下列命令觀察中斷的變化情況:

$ watch -d cat /proc/interrupts

分析步驟和總結(jié)
??1. 通過(guò) vmstat 查看服務(wù)的總體狀態(tài),包括CPU 使用率、上下文切換次數(shù)、有序隊(duì)列和中斷次數(shù)(四個(gè)關(guān)鍵指標(biāo))。
??2. 通過(guò) pidstat 查看進(jìn)程的上下文切換情況,定位到進(jìn)程或者線程。
??3. 通過(guò)查看/proc/interrupts 文件確定中斷發(fā)生的類型和次數(shù)。
??自愿上下文切換次數(shù)變多,說(shuō)明進(jìn)程在等待資源,有可能發(fā)生了 io或者其他問(wèn)題;非自愿上下文切換次數(shù)變多,說(shuō)明進(jìn)程都在爭(zhēng)搶CPU,說(shuō)明CPU變成了瓶頸;中斷次數(shù)變多,說(shuō)明 CPU被中斷處理程序占用,需要查看/proc/interrupts 文件分析具體的中斷類型。

CPU達(dá)到100%應(yīng)該怎么辦

如何查看CPU使用率

查看CPU的使用率,第一反應(yīng)肯定是topps工具:

  • top:現(xiàn)實(shí)系統(tǒng)總體的 CPU和內(nèi)存情況,以及各個(gè)進(jìn)程的資源使用情況。
  • ps :顯示每個(gè)進(jìn)程的資源使用情況。
    比如下列就為 top 命令的輸出情況:
$ top
top - 15:29:09 up 3 days, 19:13,  2 users,  load average: 0.02, 0.02, 0.49
Tasks: 135 total,   3 running, 132 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  6.7 sy,  0.0 ni, 93.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1887.8 total,    304.7 free,    300.5 used,   1282.5 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   1400.1 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                               
      1 root      20   0  104512  12152   9112 S   0.0   0.6   0:04.57 systemd                                                                                                                                               
      2 root      20   0       0      0      0 S   0.0   0.0   0:00.02 kthreadd

??其中第三行就為系統(tǒng)的 CPU使用率,不過(guò)默認(rèn)展示的所有 CPU的平均值,只需要按下數(shù)字 1,就可以切換到每個(gè)CPU的使用率了。下方空白行之后是進(jìn)程的實(shí)時(shí)信息,每個(gè)進(jìn)程都有一個(gè) %CPU列,標(biāo)識(shí)該進(jìn)程的 CPU使用情況,不過(guò) top工具并沒(méi)有細(xì)分進(jìn)程的用戶態(tài)CPU還是內(nèi)核態(tài)CPU,可以使用 pidstat工具查看更加詳細(xì)的信息。

$ pidstat 1 5
                       進(jìn)程號(hào)  用戶態(tài)  系統(tǒng)態(tài)  運(yùn)行虛擬機(jī)  等待CPU  總的
03:40:28 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
03:40:29 PM     0      1058    1.00    0.00    0.00    0.00    1.00     0  AliYunDun
03:40:29 PM     0      1120    1.00    0.00    0.00    0.00    1.00     0  AliYunDunMonito
03:40:29 PM     0     21088    0.00    1.00    0.00    0.00    1.00     0  pidstat
CPU使用率過(guò)高怎么辦

??通過(guò)top、ps、pidstat等工具,可以輕松的找到CPU使用率較高的進(jìn)程,那如何找到占用 CPU到底是代碼里的哪個(gè)函數(shù)呢?可以通過(guò) perf 工具來(lái)完成,它是一個(gè)基于性能事件采樣為基礎(chǔ),不僅可以分析系統(tǒng)的各種事件和內(nèi)核性能,還可以分析指定應(yīng)用程序的性能問(wèn)題。

CPU使用率過(guò)高,但是無(wú)法找到高CPU的應(yīng)用

??系統(tǒng)的CPU使用率,不僅包含進(jìn)程用戶態(tài)和內(nèi)核態(tài)的運(yùn)行,還包括中斷處理、等待IO以及內(nèi)核線程等,所以當(dāng)系統(tǒng)的CPU過(guò)高時(shí),不一定能找到對(duì)應(yīng)的高CPU使用率的進(jìn)程
??所以,如果通過(guò)top命令發(fā)現(xiàn)系統(tǒng)的整體CPU命令很高,但是無(wú)論是根據(jù)下方進(jìn)程列表的展示還是通過(guò)其他的工具(pidstat)查看,都找不到高CPU使用率的進(jìn)程時(shí),有可能為下面這些情況:

  • 應(yīng)用里直接調(diào)用了其他二進(jìn)制程序,這些程序的通常運(yùn)行時(shí)間比較短,通過(guò)top工具也不容易發(fā)現(xiàn)。
  • 應(yīng)用本身在不停的崩潰重啟,而啟動(dòng)過(guò)程的資源初始化,很可能會(huì)占用相當(dāng)多的CPU。
  • 這些進(jìn)程都為短時(shí)進(jìn)程,運(yùn)行很短的時(shí)間就會(huì)結(jié)束,很難通過(guò)top這種間隔時(shí)間較長(zhǎng)的工具發(fā)現(xiàn)。
    分析步驟和總結(jié)
    ??1. 通過(guò)top命令,觀察就緒隊(duì)列中的進(jìn)程數(shù)量(第二行 tasksrunning 字段的值)和下方展示的進(jìn)程列表中運(yùn)行態(tài)的進(jìn)程數(shù)量是否存在較大的誤差。
    ??2. 通過(guò)pidstat 命令查看可能出現(xiàn)問(wèn)題的活躍進(jìn)程的信息。
    ??3. 觀察 top命令的輸出,下方的進(jìn)程列表中某個(gè)進(jìn)程的 pid 是否不斷變化。
    ??4. 通過(guò) pstree命令,找出該進(jìn)程的父進(jìn)程,然后進(jìn)入app進(jìn)行內(nèi)部分析,尋找不斷創(chuàng)建子進(jìn)程的原因所在。
    ??在得到猜測(cè)的結(jié)果之后,我們需要驗(yàn)證該猜測(cè)到底是否正確,所以我們可以使用 perf工具或者專門為短時(shí)進(jìn)程設(shè)計(jì)的工具 execsnoop來(lái)驗(yàn)證猜想。execsnoop通過(guò) ftrace 實(shí)時(shí)監(jiān)控進(jìn)程的 exec()行為,并輸出短時(shí)進(jìn)程的基本信息,包括進(jìn)程pid、父進(jìn)程pid、命令行參數(shù)以及執(zhí)行的結(jié)果。
系統(tǒng)中出現(xiàn)了大量的不可中斷進(jìn)程和僵尸進(jìn)程

??在top命令的 s(進(jìn)程狀態(tài))列中包含以下幾種狀態(tài):

d: 不可中斷睡眠(uninterruptible sleep), 表示進(jìn)程正在和硬件交互,不允許被其他進(jìn)程打斷。
I: 空閑(idle)。
R: 運(yùn)行(running)。
S: 可中斷睡眠(sleep),表示進(jìn)程正在等待某個(gè)事件而被系統(tǒng)掛起。當(dāng)進(jìn)程等待的事件發(fā)生時(shí),它會(huì)被喚醒并進(jìn)入R狀態(tài)。
Z: 僵尸進(jìn)程 (Zombile),表示進(jìn)程已經(jīng)結(jié)束,但是父進(jìn)程還沒(méi)有回收它的資源(比如進(jìn)程描述符、PID等)
T/t: 忽略

??僵尸進(jìn)程是多進(jìn)程應(yīng)用容易碰到的問(wèn)題。正常情況下,當(dāng)一個(gè)進(jìn)程創(chuàng)建了子進(jìn)程后,它應(yīng)該通過(guò)系統(tǒng)調(diào)用 wait()waitpid() 等待子進(jìn)程結(jié)束,回收子進(jìn)程的資源;而在子進(jìn)程結(jié)束時(shí),會(huì)向父進(jìn)程發(fā)送SIGCHLD信號(hào),所以父進(jìn)程還可以注冊(cè)SIGCHLD信號(hào)的處理函數(shù),異步回收資源。
??如果父進(jìn)程沒(méi)有處理子進(jìn)程的狀態(tài),子進(jìn)程就提前退出,這是子進(jìn)程就會(huì)變成僵尸進(jìn)程。通常情況下,僵尸進(jìn)程的持續(xù)時(shí)間較短,在父進(jìn)程回收它的資源就會(huì)消亡;或者由init進(jìn)程回收后也會(huì)消亡。
??一旦父進(jìn)程沒(méi)有處理子進(jìn)程的終止,還一直保持運(yùn)行狀態(tài),那么子進(jìn)程就會(huì)一直處于僵尸狀態(tài)。大量的僵尸進(jìn)程會(huì)用盡PID進(jìn)程號(hào),導(dǎo)致不能創(chuàng)建新進(jìn)程。
分析步驟和總結(jié):
??大量不可中斷進(jìn)程

  1. 通過(guò) top命令,觀察平均負(fù)載、進(jìn)程各個(gè)狀態(tài)的數(shù)量、CPU使用率、iowait等指標(biāo)。
  2. 通過(guò)dstat 查看 iowait 升高時(shí),磁盤讀寫情況。
  3. 通過(guò) top命令觀察處于 D(不可中斷)狀態(tài)的所有進(jìn)程。
  4. 通過(guò) pidstat命令分析進(jìn)程的讀寫情況,如果該讀寫較高時(shí),著重分析該進(jìn)程的調(diào)用堆棧。
    ??僵尸進(jìn)程
  1. 通過(guò) pstree 命令找出僵尸進(jìn)程的父進(jìn)程。
  2. 著重分析該進(jìn)程的運(yùn)行情況。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容