星空無限傳媒官網(wǎng)免費下載seo服務收費
(上)
本文涉及案例來自于學習極客時間專欄《Linux性能優(yōu)化實戰(zhàn)》精心整理而來,案例總結不到位的請各位多多指正。
某個應用的CPU使用率居然達到100%,我該怎么辦?
分析過程
- 使用觀察系統(tǒng)CPU使用情況(并按下數(shù)字 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
這里可以看到,系統(tǒng)中有幾個 php-fpm 進程的 CPU 使用率加起來接近 200%;而每個 CPU 的用戶使用率(us)也已經(jīng)超過了 98%,接近飽和。這樣,我們就可以確認,正是用戶空間的 php-fpm 進程,導致 CPU 使用率驟升
- 使用perf在進一步定位程序的函數(shù)調用開銷
# -g開啟調用關系分析,-p指定php-fpm的進程號21515
$ perf top -g -p 21515
按方向鍵切換到 php-fpm,再按下回車鍵展開 php-fpm 的調用關系,你會發(fā)現(xiàn),調用關系最終到了 sqrt 和 add_function
總結
CPU 使用率是最直觀和最常用的系統(tǒng)性能指標,更是我們在排查性能問題時,更要熟悉它每個指標的的含義,尤其要弄清楚用戶(%user)、Nice(%nice)、系統(tǒng)(%system) 、等待 I/O(%iowait) 、中斷(%irq)以及軟中斷(%softirq)這幾種不同 CPU 的使用率。比如說:
- 用戶 CPU 和 Nice CPU 高,說明用戶態(tài)進程占用了較多的 CPU,所以應該著重排查進程的性能問題。
- 系統(tǒng) CPU 高,說明內(nèi)核態(tài)占用了較多的 CPU,所以應該著重排查內(nèi)核線程或者系統(tǒng)調用的性能問題。
- I/O 等待 CPU 高,說明等待 I/O 的時間比較長,所以應該著重排查系統(tǒng)存儲是不是出現(xiàn)了 I/O 問題。
- 軟中斷和硬中斷高,說明軟中斷或硬中斷的處理程序占用了較多的 CPU,所以應該著重排查內(nèi)核中的中斷服務程序。
碰到 CPU 使用率升高的問題,你可以借助 top、pidstat 等工具,確認引發(fā) CPU 性能問題的來源;再使用 perf 等工具,排查出引起性能問題的具體函數(shù)。
系統(tǒng)的 CPU 使用率很高,但為啥卻找不到高 CPU 的應用?
分析過程
- 依然是使用top,觀察系統(tǒng)CPU使用情況
$ top
...
%Cpu(s): 80.8 us, 15.1 sy, 0.0 ni, 2.8 id, 0.0 wa, 0.0 hi, 1.3 si, 0.0 st
...
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6882 root 20 0 8456 5052 3884 S 2.7 0.1 0:04.78 docker-containe
6947 systemd+ 20 0 33104 3716 2340 S 2.7 0.0 0:04.92 nginx
7494 daemon 20 0 336696 15012 7332 S 2.0 0.2 0:03.55 php-fpm
7495 daemon 20 0 336696 15160 7480 S 2.0 0.2 0:03.55 php-fpm
10547 daemon 20 0 336696 16200 8520 S 2.0 0.2 0:03.13 php-fpm
10155 daemon 20 0 336696 16200 8520 S 1.7 0.2 0:03.12 php-fpm
10552 daemon 20 0 336696 16200 8520 S 1.7 0.2 0:03.12 php-fpm
15006 root 20 0 1168608 66264 37536 S 1.0 0.8 9:39.51 dockerd
4323 root 20 0 0 0 0 I 0.3 0.0 0:00.87 kworker/u4:1
通過以上輸出分析
- 系統(tǒng)的整體 CPU 使用率是比較高的: 用戶CPU到了80%,系統(tǒng)CPU為15.1%,空閑CPU只有2.8%。(用戶CPU使用率高,肯定是有用戶進程占用CPU導致)
- CPU 使用率最高的進程也只不過才 2.7%,并不高
- 觀察進程狀態(tài)發(fā)現(xiàn):Nginx 和所有的 php-fpm 都處于?Sleep(S)狀態(tài),而真正處于 Running(R)狀態(tài)的,卻是幾個 stress 進程
- 使用pidstat命令分析stress進程
# 使用 -p 選項指定stress進程的 PID
$ pidstat -p 2434416:14:55 UID PID %usr %system %guest %wait %CPU CPU Command
沒有任何輸出。現(xiàn)在終于發(fā)現(xiàn)問題,原來這個進程已經(jīng)不存在了,所以 pidstat 就沒有任何輸出,而且從top的輸出我們看到stress的PID一直在變化,出現(xiàn)這種情況的無非就兩個原因:
- 第一個原因,進程在不停地崩潰重啟,比如因為段錯誤、配置錯誤等等,這時,進程在退出后可能又被監(jiān)控系統(tǒng)自動重啟了。
- 第二個原因,這些進程都是短時進程,也就是在其他應用內(nèi)部通過 exec 調用的外面命令。這些命令一般都只運行很短的時間就會結束,你很難用 top 這種間隔時間比較長的工具發(fā)現(xiàn)(上面的案例,我們碰巧發(fā)現(xiàn)了)。
- 使用pstree查詢下stress進程的父進程
$ pstree | grep stress|-docker-containe-+-php-fpm-+-php-fpm---sh---stress| |-3*[php-fpm---sh---stress---stress]
從這里可以看到,stress 是被 php-fpm 調用的子進程,并且進程數(shù)量不止一個(這里是 3 個),接下來就是去看php-fpm的內(nèi)部代碼邏輯了,不在展開
- 使用perf繼續(xù)分析下stress的cpu占用函數(shù)
# 記錄性能事件,等待大約15秒后按 Ctrl+C 退出
$ perf record -g# 查看報告
$ perf report
perf輸出分析:
- stress 占了所有 CPU 時鐘事件的 77%,而 stress 調用調用棧中比例最高的,是隨機數(shù)生成函數(shù) random(),看來它的確就是 CPU 使用率升高的元兇了。
總結
碰到常規(guī)問題無法解釋的 CPU 使用率情況時,首先要想到有可能是短時應用導致的問題,比如有可能是下面這兩種情況。
- 第一,應用里直接調用了其他二進制程序,這些程序通常運行時間比較短,通過 top 等工具也不容易發(fā)現(xiàn)。
- 第二,應用本身在不停地崩潰重啟,而啟動過程的資源初始化,很可能會占用相當多的 CPU。
對于短時進程,我們可以通過pstree命令找到它們的父進程,再從父進程所在的應用入手,排查問題的根源
(中)
在前一篇文章?Linux系統(tǒng)下CPU性能問題分析案例(上)中我們看到的系統(tǒng)CPU使用率高的表現(xiàn)都是用戶態(tài)(us)下使用率過高場景的排查過程,關于CPU使用率相關重要指標,我們經(jīng)常在使用top、dstat、vmstat等工具看到,這里解讀一下:
- user(通常縮寫為us),代表用戶態(tài)CPU時間
- nice(通??s寫為ni),代表低優(yōu)先級用戶態(tài)CPU時間,nice可取值范圍是-20到19,數(shù)值越大,優(yōu)先級反而越低,默認值是0
- system(通常縮寫為sys),代表內(nèi)核態(tài)CPU時間
- idle(通??s寫為id),代表空閑時間。注意,它不包括等待I/O的時間(iowait)
- iowait(通常縮寫為wa),代表等待 I/O的CPU時間
- irq(通??s寫為hi),代表處理硬中斷的CPU時間
- softirq(通??s寫為si),代表處理軟中斷的CPU時間
- steal(通??s寫為st),代表當系統(tǒng)運行在虛擬機中的時候,虛擬機占用的CPU時間
- guest(通??s寫為guest),代表通過虛擬化運行其他操作系統(tǒng)的時間,也就是運行虛擬機的CPU時間
- guest_nice(通常縮寫為gnice),代表以低優(yōu)先級運行虛擬機的時間
CPU的iowait突然升高,我該怎么處理?
分析過程
從上面的介紹可以看出,iowait升高,第一反應會想到查看系統(tǒng)的 I/O情況,I/O又分為磁盤I/O和網(wǎng)絡I/O,這里先分析磁盤I/O
1.運行 dstat 命令,觀察 CPU 和 I/O 的使用情況
- 結果分析
- 在iowait升高(wai)時,磁盤的讀請求(read)都很高,最高時1271M
- 充分說明iowait的升高是磁盤I/O導致的,確切的說,是大量讀磁盤導致的
2.通過pidstat查詢進程的I/O情況
# -d:統(tǒng)計進程的磁盤使用情況 1: 采集周期1s 10: 采集10次
pidstat -d 1 10
- 結果分析
- 大量讀磁盤的進程名稱是app,而且app進程的pid在不停變化(短時進程?)
3.使用ps命令查看下app進程
- 結果分析
- 進程的狀態(tài)是Z+,命令行參數(shù)<defunct>,進程變成僵尸進程了
- 僵尸進程的產(chǎn)生和處理方法,這里暫不展開,有想了解的可以評論留言或者自行學習
- app的是誰創(chuàng)建的,是下一步分析的重點
4.查詢app進程的父進程
- 結果分析
- pid為51780的父進程id是51688,進程名稱也是app
5.使用perf命令采集性能事件分析app函數(shù)調用
# 錄制全局性能事件,如果只想錄制某個進程的,可以使用-p指定
# perf record -ag -p {pid} -- sleep 10 #采集指定pid所有cpu的性能事件,周期是10s
perf record -g# 分析報告
perf report
- 分析結果
- app進程正在對磁盤進行直接讀,也就是繞過了系統(tǒng)緩存,每個讀請求都會從磁盤直接讀
思路總結
- 使用dstat命令查看系統(tǒng)I/O情況(dstat可以同時觀察cpu和磁盤的情況)
- 使用pidstat命令可以定位到進程維度的磁盤讀寫情況,找出可疑進程
- 使用ps、top等命令可以觀測到進程的狀態(tài)(D、R、S、Z、T等)
- 使用pstree命令我們找出了app進程的父進程(子進程的pid一直在變)
- 使用perf命令就可以對進程的函數(shù)調用關系分析了
- 沒啥需要使用的啦。哈哈,點贊+收藏
知識補充
- 進程狀態(tài)
- R?是Running或Runnable 的縮寫,表示進程在CPU的就緒隊列中,正在運行或者正在等待運行
- D?是Disk Sleep的縮寫,也就是不可中斷狀態(tài)睡眠(Uninterruptible Sleep),一般表示進程正在跟硬件交互,并且交互過程不允許被其他進程或中斷打斷。
- Z?是Zombie的縮寫,進程實際上已經(jīng)結束了,但是父進程還沒有回收它的資源(比如進程的描述符、PID 等)
- S?是Interruptible Sleep的縮寫,也就是可中斷狀態(tài)睡眠,表示進程因為等待某個事件而被系統(tǒng)掛起。當進程等待的事件發(fā)生時,它會被喚醒并進入R狀態(tài)
- I?是Idle的縮寫,也就是空閑狀態(tài),用在不可中斷睡眠的內(nèi)核線程上
- T 或者 t,也就是Stopped或Traced的縮寫,表示進程處于暫?;蛘吒櫊顟B(tài)
- 僵尸進程
- 一旦父進程沒有處理子進程的終止,還一直保持運行狀態(tài),那么子進程就會一直處于僵尸狀態(tài)
- 大量的僵尸進程會用盡PID進程號,導致新進程不能創(chuàng)建
- 僵尸進程在父進程回收它的資源后就會消亡,或者在父進程退出后,由init進程回收后也會消亡
你在日常工作中是如何分析CPU的iowait升高的過程的?歡迎一起交流、一起討論。無論是編碼的樂趣還是系統(tǒng)的構建,讓我們共同在這個科技的大舞臺上創(chuàng)造奇跡。
(下)
在我的前一篇文章?Linux系統(tǒng)下CPU性能問題分析案例(中)中介紹了CPU使用率的重要指標,包括User、System、Idle、IOwait、Irq、Softirq、Steal、Guest等CPU時間的說明,通過具體案例分析了User、Iowait等CPU使用率過高的排查思路,感興趣的可以回去翻看,今天我們來對看下中斷對CPU影響的案例和分析過程。
基本概念
- 我們常說的中斷是什么?
- 硬中斷:
- 概念:?硬中斷是由硬件設備發(fā)送給CPU的一種中斷信號。這可以是來自外部設備(如磁盤、網(wǎng)絡接口卡、鍵盤)的信號,需要CPU的處理。
- 工作原理:?當硬件設備需要CPU的處理時,它會發(fā)送一個硬中斷信號,中斷控制器接收到信號后將其傳遞給CPU。CPU會立即中斷當前執(zhí)行的任務,保存當前狀態(tài),然后執(zhí)行與中斷相關的中斷處理程序。(硬件觸發(fā),快速執(zhí)行)
- 軟中斷:
- 概念:?軟中斷是由軟件生成的中斷信號,通常是由內(nèi)核或操作系統(tǒng)的組件觸發(fā)的,而不是外部硬件設備。
- 工作原理:?軟中斷是通過在內(nèi)存中設置一個特殊的中斷標志位來觸發(fā)的。當CPU執(zhí)行到一個允許軟中斷的位置時,它會檢查這個標志位,如果被設置,CPU將跳轉到相應的軟中斷處理程序執(zhí)行。(內(nèi)核觸發(fā),延遲執(zhí)行)
- 中斷處理程序:
- 概念:?中斷處理程序是用于響應中斷事件的一段代碼,它負責處理中斷并執(zhí)行必要的操作。
- 工作原理:?當中斷被觸發(fā),CPU會跳轉到相應的中斷處理程序。中斷處理程序執(zhí)行與中斷相關的任務,可能包括保存當前狀態(tài)、處理中斷源產(chǎn)生的事件、執(zhí)行特定的操作,最后恢復先前的執(zhí)行狀態(tài)。
- 如何查看軟中斷和內(nèi)核線程?
- /proc/interrupts 提供了硬中斷的運行情況(系統(tǒng)硬件觸發(fā),不需要太關注)
- /proc/softirqs 提供了軟中斷的運行情況(下圖中第一列是中斷類型,后面案例分析會說到)
不同軟中斷類型在每個CPU上的累積運行次數(shù)
內(nèi)核中斷線程
軟中斷CPU使用率升高,我該怎么辦?
- 案例現(xiàn)象
- 軟中斷線程(ksoftirqd/1)使用率超高,處理中斷的CPU占比也很高
- 分析過程
1.使用watch動態(tài)觀測,確認是什么類型的軟中斷?
watch -d "/bin/cat /proc/softirqs"
- 分析結果
- TIMER(定時中斷)、 NET_RX(網(wǎng)絡接收)、SCHED(內(nèi)核調度)、RCU(RCU 鎖)等這幾個軟中斷都在不停變化
- 而?NET_RX,就是網(wǎng)絡數(shù)據(jù)包接收軟中斷的變化速率最快
- 其他幾種類型的軟中斷,是保證 Linux 調度、時鐘、臨界區(qū)保護這些正常工作所必需的,所以有變化時正常的
2.使用sar查詢網(wǎng)絡收發(fā)情況
# 使用sar是因為不僅可以觀察網(wǎng)絡收發(fā)的吞吐量(BPS),還可以觀察網(wǎng)絡收發(fā)的網(wǎng)絡幀數(shù)( PPS)
sar -n DEV 1
- 分析結果
- 網(wǎng)卡ens33:每秒接收的網(wǎng)絡幀數(shù)比較大,幾乎達到8w,而發(fā)送的網(wǎng)絡幀數(shù)較小,只有接近4w;每秒接收的千字節(jié)數(shù)只有 4611 KB,發(fā)送的千字節(jié)數(shù)更小,只有2314 KB(接收的PPS達到8w,但接收的BPS只有5k不到,網(wǎng)絡幀看起來是比較小的)
- docker0和veth04076e3:數(shù)據(jù)跟 ens33 基本一致只是發(fā)送和接收相反,發(fā)送的數(shù)據(jù)較大而接收的數(shù)據(jù)較小,這是?Linux 內(nèi)部網(wǎng)橋轉發(fā)導致的,屬于正常情況
3.使用tcpdump抓包一探究竟
tcpdump -i ens33 -n tcp port 80
- 分析結果
- Flags [S]:?表示這是一個SYN包。而且是大量的SYN在發(fā)過來,很明顯這就是SYN FLOOD攻擊
- SYN FLOOD解決方法
- 如果有防護設備(F5等),通過硬件來防護
- 利用iptables臨時封掉攻擊的IP或IP號段,也可以根據(jù)訪問頻次來限制
- 優(yōu)化系統(tǒng)內(nèi)核相關參數(shù),增加抵御能力。這個后期會在后期單獨詳細解決
歡迎一起交流、一起討論。無論是編碼的樂趣還是系統(tǒng)的構建,讓我們共同在這個科技的大舞臺上創(chuàng)造奇跡。