07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)
生活随笔
收集整理的這篇文章主要介紹了
07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上一節(jié),我用一個(gè) Nginx+PHP 的案例,給你講了服務(wù)器 CPU 使用率高的分析和應(yīng)對(duì)方法。這里你一定要記得,當(dāng)碰到無(wú)法解釋的 CPU 使用率問(wèn)題時(shí),先要檢查一下是不是短時(shí)應(yīng)用在搗鬼。短時(shí)應(yīng)用的運(yùn)行時(shí)間比較短,很難在 top 或者 ps 這類展示系統(tǒng)概要和進(jìn)程快照的工具中發(fā)現(xiàn),你需要使用記錄事件的工具來(lái)配合診斷,比如 execsnoop 或者 perf top。這些思路你不用刻意去背,多練習(xí)幾次,多在操作中思考,你便能靈活運(yùn)用。另外,我們還講到 CPU 使用率的類型。除了上一節(jié)提到的用戶 CPU 之外,它還包括系統(tǒng) CPU(比如上下文切換)、等待 I/O 的 CPU(比如等待磁盤(pán)的響應(yīng))以及中斷 CPU(包括軟中斷和硬中斷)等。我們已經(jīng)在上下文切換的文章中,一起分析了系統(tǒng) CPU 使用率高的問(wèn)題,剩下的等待 I/O 的 CPU 使用率(以下簡(jiǎn)稱為 iowait)升高,也是最常見(jiàn)的一個(gè)服務(wù)器性能問(wèn)題。今天我們就來(lái)看一個(gè)多進(jìn)程 I/O 的案例,并分析這種情況。
進(jìn)程狀態(tài)
當(dāng) iowait 升高時(shí),進(jìn)程很可能因?yàn)榈貌坏接布捻憫?yīng),而長(zhǎng)時(shí)間處于不可中斷狀態(tài)。從 ps 或者 top 命令的輸出中,你可以發(fā)現(xiàn)它們都處于 D 狀態(tài),也就是不可中斷狀態(tài)(Uninterruptible Sleep)。既然說(shuō)到了進(jìn)程的狀態(tài),進(jìn)程有哪些狀態(tài)你還記得嗎?我們先來(lái)回顧一下。top 和 ps 是最常用的查看進(jìn)程狀態(tài)的工具,我們就從 top 的輸出開(kāi)始。下面是一個(gè) top 命令輸出的示例,S 列(也就是 Status 列)表示進(jìn)程的狀態(tài)。從這個(gè)示例里,你可以看到 R、D、Z、S、I 等幾個(gè)狀態(tài),它們分別是什么意思呢?$ topPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 28961 root 20 0 43816 3148 4040 R 3.2 0.0 0:00.01 top620 root 20 0 37280 33676 908 D 0.3 0.4 0:00.01 app1 root 20 0 160072 9416 6752 S 0.0 0.1 0:37.64 systemd1896 root 20 0 0 0 0 Z 0.0 0.0 0:00.00 devapp2 root 20 0 0 0 0 S 0.0 0.0 0:00.10 kthreadd4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq7 root 20 0 0 0 0 S 0.0 0.0 0:06.37 ksoftirqd/0我們挨個(gè)來(lái)看一下:- R 是 Running 或 Runnable 的縮寫(xiě),表示進(jìn)程在 CPU 的就緒隊(duì)列中,正在運(yùn)行或者正在等待運(yùn)行。
- D 是 Disk Sleep 的縮寫(xiě),也就是不可中斷狀態(tài)睡眠(Uninterruptible Sleep),一般表示進(jìn)程正在跟硬件交互,并且交互過(guò)程不允許被其他進(jìn)程或中斷打斷。
- Z 是 Zombie 的縮寫(xiě),如果你玩過(guò)“植物大戰(zhàn)僵尸”這款游戲,應(yīng)該知道它的意思。它表示僵尸進(jìn)程,也就是進(jìn)程實(shí)際上已經(jīng)結(jié)束了,但是父進(jìn)程還沒(méi)有回收它的資源(比如進(jìn)程的描述符、PID 等)。
- S 是 Interruptible Sleep 的縮寫(xiě),也就是可中斷狀態(tài)睡眠,表示進(jìn)程因?yàn)榈却硞€(gè)事件而被系統(tǒng)掛起。當(dāng)進(jìn)程等待的事件發(fā)生時(shí),它會(huì)被喚醒并進(jìn)入 R 狀態(tài)。
- I 是 Idle 的縮寫(xiě),也就是空閑狀態(tài),用在不可中斷睡眠的內(nèi)核線程上。前面說(shuō)了,硬件交互導(dǎo)致的不可中斷進(jìn)程用 D 表示,但對(duì)某些內(nèi)核線程來(lái)說(shuō),它們有可能實(shí)際上并沒(méi)有任何負(fù)載,用 Idle 正是為了區(qū)分這種情況。要注意,D 狀態(tài)的進(jìn)程會(huì)導(dǎo)致平均負(fù)載升高, I 狀態(tài)的進(jìn)程卻不會(huì)。
案例分析
接下來(lái),我將用一個(gè)多進(jìn)程應(yīng)用的案例,帶你分析大量不可中斷狀態(tài)和僵尸狀態(tài)進(jìn)程的問(wèn)題。這個(gè)應(yīng)用基于 C 開(kāi)發(fā),由于它的編譯和運(yùn)行步驟比較麻煩,我把它打包成了一個(gè) Docker 鏡像。這樣,你只需要運(yùn)行一個(gè) Docker 容器就可以得到模擬環(huán)境。你的準(zhǔn)備
下面的案例仍然基于 Ubuntu 18.04,同樣適用于其他的 Linux 系統(tǒng)。我使用的案例環(huán)境如下所示:機(jī)器配置:2 CPU,8GB 內(nèi)存預(yù)先安裝 docker、sysstat、dstat 等工具,如 apt install docker.io dstat sysstat這里,dstat 是一個(gè)新的性能工具,它吸收了 vmstat、iostat、ifstat 等幾種工具的優(yōu)點(diǎn),可以同時(shí)觀察系統(tǒng)的 CPU、磁盤(pán) I/O、網(wǎng)絡(luò)以及內(nèi)存使用情況。接下來(lái),我們打開(kāi)一個(gè)終端,SSH 登錄到機(jī)器上,并安裝上述工具。注意,以下所有命令都默認(rèn)以 root 用戶運(yùn)行,如果你用普通用戶身份登陸系統(tǒng),請(qǐng)運(yùn)行 sudo su root 命令切換到 root 用戶。如果安裝過(guò)程有問(wèn)題,你可以先上網(wǎng)搜索解決,實(shí)在解決不了的,記得在留言區(qū)向我提問(wèn)。溫馨提示:案例應(yīng)用的核心代碼邏輯比較簡(jiǎn)單,你可能一眼就能看出問(wèn)題,但實(shí)際生產(chǎn)環(huán)境中的源碼就復(fù)雜多了。所以,我依舊建議,操作之前別看源碼,避免先入為主,而要把它當(dāng)成一個(gè)黑盒來(lái)分析,這樣你可以更好地根據(jù)現(xiàn)象分析問(wèn)題。你姑且當(dāng)成你工作中的一次演練,這樣效果更佳。操作和分析
安裝完成后,我們首先執(zhí)行下面的命令運(yùn)行案例應(yīng)用:$ docker run --privileged --name=app -itd feisky/app:iowait然后,輸入 ps 命令,確認(rèn)案例應(yīng)用已正常啟動(dòng)。如果一切正常,你應(yīng)該可以看到如下所示的輸出:$ ps aux | grep /app root 4009 0.0 0.0 4376 1008 pts/0 Ss+ 05:51 0:00 /app root 4287 0.6 0.4 37280 33660 pts/0 D+ 05:54 0:00 /app root 4288 0.6 0.4 37280 33668 pts/0 D+ 05:54 0:00 /app從這個(gè)界面,我們可以發(fā)現(xiàn)多個(gè) app 進(jìn)程已經(jīng)啟動(dòng),并且它們的狀態(tài)分別是 Ss+ 和 D+。其中,S 表示可中斷睡眠狀態(tài),D 表示不可中斷睡眠狀態(tài),我們?cè)谇懊鎰倢W(xué)過(guò),那后面的 s 和 + 是什么意思呢?不知道也沒(méi)關(guān)系,查一下 man ps 就可以。現(xiàn)在記住,s 表示這個(gè)進(jìn)程是一個(gè)會(huì)話的領(lǐng)導(dǎo)進(jìn)程,而 + 表示前臺(tái)進(jìn)程組。這里又出現(xiàn)了兩個(gè)新概念,進(jìn)程組和會(huì)話。它們用來(lái)管理一組相互關(guān)聯(lián)的進(jìn)程,意思其實(shí)很好理解。進(jìn)程組表示一組相互關(guān)聯(lián)的進(jìn)程,比如每個(gè)子進(jìn)程都是父進(jìn)程所在組的成員;而會(huì)話是指共享同一個(gè)控制終端的一個(gè)或多個(gè)進(jìn)程組。比如,我們通過(guò) SSH 登錄服務(wù)器,就會(huì)打開(kāi)一個(gè)控制終端(TTY),這個(gè)控制終端就對(duì)應(yīng)一個(gè)會(huì)話。而我們?cè)诮K端中運(yùn)行的命令以及它們的子進(jìn)程,就構(gòu)成了一個(gè)個(gè)的進(jìn)程組,其中,在后臺(tái)運(yùn)行的命令,構(gòu)成后臺(tái)進(jìn)程組;在前臺(tái)運(yùn)行的命令,構(gòu)成前臺(tái)進(jìn)程組。明白了這些,我們?cè)儆?top 看一下系統(tǒng)的資源使用情況:# 按下數(shù)字 1 切換到所有 CPU 的使用情況,觀察一會(huì)兒按 Ctrl+C 結(jié)束 $ top top - 05:56:23 up 17 days, 16:45, 2 users, load average: 2.00, 1.68, 1.39 Tasks: 247 total, 1 running, 79 sleeping, 0 stopped, 115 zombie %Cpu0 : 0.0 us, 0.7 sy, 0.0 ni, 38.9 id, 60.5 wa, 0.0 hi, 0.0 si, 0.0 st %Cpu1 : 0.0 us, 0.7 sy, 0.0 ni, 4.7 id, 94.6 wa, 0.0 hi, 0.0 si, 0.0 st ...PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND4340 root 20 0 44676 4048 3432 R 0.3 0.0 0:00.05 top4345 root 20 0 37280 33624 860 D 0.3 0.0 0:00.01 app4344 root 20 0 37280 33624 860 D 0.3 0.4 0:00.01 app1 root 20 0 160072 9416 6752 S 0.0 0.1 0:38.59 systemd ...從這里你能看出什么問(wèn)題嗎?細(xì)心一點(diǎn),逐行觀察,別放過(guò)任何一個(gè)地方。忘了哪行參數(shù)意思的話,也要及時(shí)返回去復(fù)習(xí)。好的,如果你已經(jīng)有了答案,那就繼續(xù)往下走,看看跟我找的問(wèn)題是否一樣。這里,我發(fā)現(xiàn)了四個(gè)可疑的地方。先看第一行的平均負(fù)載( Load Average),過(guò)去 1 分鐘、5 分鐘和 15 分鐘內(nèi)的平均負(fù)載在依次減小,說(shuō)明平均負(fù)載正在升高;而 1 分鐘內(nèi)的平均負(fù)載已經(jīng)達(dá)到系統(tǒng)的 CPU 個(gè)數(shù),說(shuō)明系統(tǒng)很可能已經(jīng)有了性能瓶頸。再看第二行的 Tasks,有 1 個(gè)正在運(yùn)行的進(jìn)程,但僵尸進(jìn)程比較多,而且還在不停增加,說(shuō)明有子進(jìn)程在退出時(shí)沒(méi)被清理。接下來(lái)看兩個(gè) CPU 的使用率情況,用戶 CPU 和系統(tǒng) CPU 都不高,但 iowait 分別是 60.5% 和 94.6%,好像有點(diǎn)兒不正常。最后再看每個(gè)進(jìn)程的情況, CPU 使用率最高的進(jìn)程只有 0.3%,看起來(lái)并不高;但有兩個(gè)進(jìn)程處于 D 狀態(tài),它們可能在等待 I/O,但光憑這里并不能確定是它們導(dǎo)致了 iowait 升高。我們把這四個(gè)問(wèn)題再匯總一下,就可以得到很明確的兩點(diǎn):- 第一點(diǎn),iowait 太高了,導(dǎo)致系統(tǒng)的平均負(fù)載升高,甚至達(dá)到了系統(tǒng) CPU 的個(gè)數(shù)。
- 第二點(diǎn),僵尸進(jìn)程在不斷增多,說(shuō)明有程序沒(méi)能正確清理子進(jìn)程的資源。
小結(jié)
今天我們主要通過(guò)簡(jiǎn)單的操作,熟悉了幾個(gè)必備的進(jìn)程狀態(tài)。用我們最熟悉的 ps 或者 top ,可以查看進(jìn)程的狀態(tài),這些狀態(tài)包括運(yùn)行(R)、空閑(I)、不可中斷睡眠(D)、可中斷睡眠(S)、僵尸(Z)以及暫停(T)等。其中,不可中斷狀態(tài)和僵尸狀態(tài),是我們今天學(xué)習(xí)的重點(diǎn)。- 不可中斷狀態(tài),表示進(jìn)程正在跟硬件交互,為了保護(hù)進(jìn)程數(shù)據(jù)和硬件的一致性,系統(tǒng)不允許其他進(jìn)程或中斷打斷這個(gè)進(jìn)程。進(jìn)程長(zhǎng)時(shí)間處于不可中斷狀態(tài),通常表示系統(tǒng)有 I/O 性能問(wèn)題。
- 僵尸進(jìn)程表示進(jìn)程已經(jīng)退出,但它的父進(jìn)程還沒(méi)有回收子進(jìn)程占用的資源。短暫的僵尸狀態(tài)我們通常不必理會(huì),但進(jìn)程長(zhǎng)時(shí)間處于僵尸狀態(tài),就應(yīng)該注意了,可能有應(yīng)用程序沒(méi)有正常處理子進(jìn)程的退出。
思考
最后,我想請(qǐng)你思考一下今天的課后題,案例中發(fā)現(xiàn)的這兩個(gè)問(wèn)題,你會(huì)怎么分析呢?又應(yīng)該怎么解決呢?你可以結(jié)合前面我們做過(guò)的案例分析,總結(jié)自己的思路,提出自己的問(wèn)題。總結(jié)
以上是生活随笔為你收集整理的07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 06 | 案例篇:系统的 CPU 使用率
- 下一篇: 08 | 案例篇:系统中出现大量不可中断