平均負(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ì)用到其中的 mpstat 和 pidstat。
??
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)程
- 通過(guò)
uptime命令查看平均負(fù)載的變化情況(過(guò)去 1 分鐘、5 分鐘、15 分鐘),由下圖終端的結(jié)果來(lái)看,平均負(fù)載時(shí)逐步增高的。
$ watch -d uptime
..., load average: 1.00, 0.75, 0.39
- 通過(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
- 通過(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é)
- 確定服務(wù)器的核心數(shù)量,通過(guò)
uptime命令觀察平均負(fù)載的趨勢(shì)走向。 - 通過(guò)
mpstat命令服務(wù)器的運(yùn)行情況, 包括cpu利用率、io等待、用戶態(tài)、系統(tǒng)態(tài)、爭(zhēng)用CPU所占時(shí)間 等各個(gè)指標(biāo)所占比例等等。 - 通過(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)容:
-
r: 就緒隊(duì)列的長(zhǎng)度,表示運(yùn)行或者等待CPU的進(jìn)程數(shù)量。 -
b:表示不可中斷睡眠狀態(tài)的進(jìn)程數(shù)。 -
in:每秒中斷次數(shù)。 -
cs: 每秒上下文切換的次數(shù)。
場(chǎng)景: 案例分析
- 首先通過(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 占用率的升高。
- 通過(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)肯定是top和 ps工具:
-
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ù)量(第二行tasks中running字段的值)和下方展示的進(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)程
- 通過(guò)
top命令,觀察平均負(fù)載、進(jìn)程各個(gè)狀態(tài)的數(shù)量、CPU使用率、iowait等指標(biāo)。 - 通過(guò)
dstat查看iowait升高時(shí),磁盤讀寫情況。 - 通過(guò)
top命令觀察處于D(不可中斷)狀態(tài)的所有進(jìn)程。 - 通過(guò)
pidstat命令分析進(jìn)程的讀寫情況,如果該讀寫較高時(shí),著重分析該進(jìn)程的調(diào)用堆棧。
??僵尸進(jìn)程
- 通過(guò)
pstree命令找出僵尸進(jìn)程的父進(jìn)程。 - 著重分析該進(jìn)程的運(yùn)行情況。