查看系統cpu個數:
(1)grep 'model name' /proc/cpuinfo|wc -l
(2)grep 'core id' /proc/cpuinfo|wc -l
性能工具的安裝:
(1)centos:yum install -y stress sysstat
(2)ubuntu:apt install stress sysstat
實戰
情景一:CPU密集型進程
(1)壓測cpu:stress --cpu 1 --timeout 600
(2)查看系統平均負載的變化:watch -d uptime
(-d 表示高亮顯示變化的區域)
(3)查看系統cpu使用率的變化情況:mpstat -P ALL 5
(-P ALL 表示監控所有的cpu,後面的數字5表示間隔5秒輸出一組數據)動態的輸出
(4)查看系統進程使用cpu情況:pidstat -u 5 2
(-u表示每隔5秒輸出一組數據,總共輸出兩次,並打印出平均數值)
情景二:I/O密集型進程
-
壓測IO:
stress --io 1 --timeout 600
- 過程如情景一
情景三:大量進程的場景
-
模擬8個進程:
stress --cpu 8 --timeout 600
- 過程如情景一
情景四:查看系統上下文切換情況
- 查看上下文切換:
vmstat 5
(每隔5秒輸出1組數據)
(1)cs(context switch)
就是每秒上下文切換的次數
(2)in(interrupt)
每秒中斷的次數
(3)r(running or runnable)
表示就緒隊列的長度,也就是正在運行和等待CPU的進程數
(4)b(blocked)
表示處於不可中斷睡眠狀態的進程數
- 查看詳細上下文切換的情況:
pidstat -w 5
(每隔5秒輸出1組數據,動態的)
(1)cswch
表示每秒自願上下文切換(voluntary context switches)的次數
(2)nvcswch
表示每秒非自願上下文切換(non voluntary context switches)的次數
- 上下文切換概念:
(1)自願上下文切換:指進程無法獲取所需資源,導致的上下文切換。比如,I/O,內存等系統資源不足時;
(2)非自願上下文切換:指進程由於時間片已到等原因,被系統強制調度,進而發生的上下文切換。比如,大量進程都在爭搶CPU時;
- 模擬多線程調度:
(1)centos:yum install -y sysbench
(2)ubuntu:apt install sysbench
- 測試:
(1)以10個線程運行5分鐘的基準測試,模擬系統多線程切換的問題:sysbench --threads=10 --max-time=300 threads run
(2)觀察上下文切換情況:vmstat 1
(3)查看cpu和上下文切換的進程和線程情況:pidstat -w -u 1
系統的就緒隊列過長,也就是正在運行和等待cpu的進程數過多,導致大量的上下文切換,而上下文切換又導致了系統cpu的佔用率升高。
(4)上圖中pidstat 默認顯示進程的指標數據,加上-t
參數後,纔會輸出線程的指標。
(5)查找源頭,注意中斷次數,是什麼類型的中斷上升呢:watch -d cat /proc/interrupts
會發現是RES(重調度中斷),這個中斷類型表示,喚醒空閒狀態的CPU來調度新的任務運行。
情景五:查看CPU使用率
- 使用工具top和ps:
(1)top:顯示系統總體的CPU和內存使用情況,以及各個進程的資源使用情況,默認每隔3秒刷新一次
空白行之後是進程的實時信息,每個進程都有一個%CPU列,表示進程的CPU使用率。
它是用戶態和內核態CPU使用率總和,包括進程用戶空間使用的CPU、通過系統調用執行的內核空間CPU、以及在就緒隊列等待運行的CPU。在虛擬化環境中,它還包括了運行虛擬機佔用的CPU。
Top並沒有細分進程的用戶態CPU和內核態CPU,那麼怎麼查看每個進程的詳細情況呢:pidstat 1 5
(每隔1秒輸出一組數據,共輸出5組 )
(2)ps:只顯示每個進程的資源使用情況
- CPU過高排查工具:想知道佔用CPU的到底是代碼裏的哪個函數,找到它,才能更高效、更針對性地進行優化。
(1)GDB(the GNU Project Debugger)
功能強大的程序調試利器,但不適合在性能分析的早期應用,因爲GDB調試程序過程會中斷程序運行,這在線上環境往往是不允許的。
(2)perf(Linux2.6.31以後內置的性能分析工具)
,它以性能事件採樣爲基礎,不僅可以分析系統的各種事件和內核性能,還可以用來分析指定應用程序的性能問題。如系統沒有,請安裝:yum install -y perf
- perf兩種常見用法:
(1)perf top類似於top,它能夠實時顯示佔用CPU時鐘最多的函數或指令,因此可以用來查找熱點函數,如下:
第一行包含三個數據,分別是:採樣數(Samples)、事件類型(event)和事件總數量(Event count)
另外注意:如果採樣數過少(比如直有十幾個),那下面的排序和百分比就沒有什麼實際參考價值了。
再往下看是一個表格式樣的數據,每一行包含四列,分別是:
第一列Overhead
,是該符號的性能事件在所有采樣中的比例,用百分比來表示。
第二列Shared
,是該函數或指令所在的動態共享對象(Dynamic Shared Object),如內核、進程名、動態鏈接庫名、內核模塊名等。
第三列Object
,是動態共享對象的類型。比如[.]表示用戶空間的可執行程序、或者動態鏈接庫,而[k]則表示內核空間。
第四列Symbol
是符號名,也就是函數名。當函數名未知時,用十六進制的地址來表示。
(2)perf record和perf report
perf top
雖然實時展示了系統的性能信息,但它缺點是不能保存數據,也就是無法用於離線或者後續的分析。
perf record
則提供了保存數據的功能,保存後的數據,需要用perf report解析展示。
實際工作中,我們還經常爲perf top和perf record加上-g
參數,開啓調用關係的採樣,方便我們根據調用鏈來分析性能問題。
比如:perf top -g -p 21515
(-g開啓調用關係分析,-p指定服務的進程號是21515)
- HTTP服務性能測試工具:
ab(apache bench)
比如:ab -c 10 -n 1000 http://192.168.246.191:80/
(併發10個請求,總共測試1000個請求)
情景六:系統的CPU使用率很高,但是找不到高CPU的應用
pidstat -p 24344
(指定PID是24344的進程)
Pstree
用樹狀形式顯示所有進程之間的關係
grep stress -r app/
(-r
目錄遞歸)
execsnoop
:一個專門爲段時進程設計的工具。它通過ftrace實時監控進程的exec()行爲,並輸出短時進程的基本信息,包括進程的PID、父進程PID、命令行參數以及執行的結果。
- 常規無法解釋的CPU使用率情況,有可能是下面這兩種情況:
(1)應用裏直接調用了其他二進制程序,這些程序通常運行時間比較短,通過top等工具不容易發現;
(2)應用本身在不停地奔潰重啓,而啓動過程的資源初始化,很可能會佔用相當多的CPU;
對於這類進程,我們可以用pstree或者execsnoop找到它們的父進程,再從父進程所在的應用入手,排查問題的根源。
注意⚠️:當碰到無法解釋的CPU使用率問題時,先要檢查下是不是短時應用在搗鬼!
情景七:系統中出現大量不可中斷進程和殭屍進程怎麼辦(上)
- 進程常見的五種狀態:
(1)R
是 Running 或 Runnable 的縮寫,表示進程在 CPU 的就緒隊列中,正在運行或者正在等待運行。
(2)D
是 Disk Sleep 的縮寫,也就是不可中斷狀態睡眠(Uninterruptible Sleep),一般表示進程正在跟硬件交互,並且交互過程不允許被其他進程或中斷打斷。
注意⚠️:進程長時間處於不可中斷狀態,通常表示系統有 I/O 性能問題。
(3)Z
是 Zombie 的縮寫,如果你玩過“植物大戰殭屍”這款遊戲,應該知道它的意思。它表示殭屍進程,也就是進程實際上已經結束了,但是父進程還沒有回收它的資源(比如進程的描述符、PID 等)。
(4)S
是 Interruptible Sleep 的縮寫,也就是可中斷狀態睡眠,表示進程因爲等待某個事件而被系統掛起。當進程等待的事件發生時,它會被喚醒並進入 R 狀態。
(5)I
是 Idle 的縮寫,也就是空閒狀態,用在不可中斷睡眠的內核線程上。前面說了,硬件交互導致的不可中斷進程用 D 表示,但對某些內核線程來說,它們有可能實際上並沒有任何負載,用 Idle 正是爲了區分這種情況。要注意,D 狀態的進程會導致平均負載升高,I 狀態的進程卻不會。
- 進程不常見的兩種狀態:
(1)T 或者 t
,也就是 Stopped 或 Traced 的縮寫,表示進程處於暫停或者跟蹤狀態。
向一個進程發送 SIGSTOP 信號,它就會因響應這個信號變成暫停狀態(Stopped);再向它發送 SIGCONT 信號,進程又會恢復運行(如果進程是終端裏直接啓動的,則需要你用 fg 命令,恢復到前臺運行)。
而當你用調試器(如 gdb)調試一個進程時,在使用斷點中斷進程後,進程就會變成跟蹤狀態,這其實也是一種特殊的暫停狀態,只不過你可以用調試器來跟蹤並按需要控制進程的運行。
(2)X
,也就是 Dead 的縮寫,表示進程已經消亡,所以你不會在top 或者 ps 命令中看到它。
注意⚠️:Ss+
:S表示可中斷睡眠狀態,s表示這個進程是一個會話的領導進程,而+表示前臺進程組。
- 進程組與會話:
它們是管理一組相互關聯的進程,意思如下:
(1)進程組表示一組相互關聯的進程,比如每個子進程都是父進程所在組的成員;
(2)會話是指共享同一個控制端的一個或多個進程組;
比如,我們通過 SSH 登錄服務器,就會打開一個控制終端(TTY),這個控制終端就對應一個會話。而我們在終端中運行的命令以及它們的子進程,就構成了一個個的進程組,,其中,在後臺運行的命令,構成後臺進程組;在前臺運行的命令,構成前臺進程組。
- 安裝dstat
(1)CentOS:yum install -y dstat
(2)Ubuntu:apt install dstat
這裏dstat是一個新的性能工具,它吸收了vmstat、iostat、ifstat等幾種工具的優點,可以同時觀察系統的CPU、磁盤I/O、網絡以及內存使用情況。
情景八:系統中出現大量不可中斷進程和殭屍進程怎麼辦(下)
- 工具使用:
(1)dstat 1 10
(間隔1秒輸出10組數據)
(2)pidstat -d -p 4344 1 3
(-d 展示 I/O 統計數據,-p 指定進程號,間隔 1 秒輸出 3 組數據)
(3)strace -p 6082
(-p指定進程號)
Strace最常用的跟蹤進程系統調用的工具。
(4)perf record -g
(終端運行十五分鐘左右,再ctrl+c)
(5)perf report
- 殭屍進程的處理
要解決殭屍進程,就要找到它的根兒,也就是找出父進程,然後在父進程裏解決。
(1)pstree -aps 3084
(-a表示輸出命令行選項,p表示PID,s表示指定進程的父進程)
運行完,你會發現 3084 號進程的父進程是 4009,也就是 app 應用。
(2)接着查看 app 應用程序的代碼,看看子進程結束的處理是否正確,比如有沒有調用wait() 或 waitpid() ,抑或是,有沒有註冊 SIGCHLD 信號的處理函數。