?Linux CPU 性能優(yōu)化指南

本文作者:allenxguo,騰訊 QQ 音樂(lè)后臺(tái)開發(fā)工程師
本文主要幫助理解 CPU 相關(guān)的性能指標(biāo),常見(jiàn)的 CPU 性能問(wèn)題以及解決方案梳理。
系統(tǒng)平均負(fù)載
簡(jiǎn)介
系統(tǒng)平均負(fù)載:是處于可運(yùn)行或不可中斷狀態(tài)的平均進(jìn)程數(shù)。
可運(yùn)行進(jìn)程:使用 CPU 或等待使用 CPU 的進(jìn)程
不可中斷狀態(tài)進(jìn)程:正在等待某些 IO 訪問(wèn),一般是和硬件交互,不可被打斷(不可被打斷的原因是為了保護(hù)系統(tǒng)數(shù)據(jù)一致,防止數(shù)據(jù)讀取錯(cuò)誤)
查看系統(tǒng)平均負(fù)載
首先top命令查看進(jìn)程運(yùn)行狀態(tài),如下:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND10760 user 20 0 3061604 84832 5956 S 82.4 0.6 126:47.61 Process29424 user 20 0 54060 2668 1360 R 17.6 0.0 0:00.03 **top**
程序狀態(tài)Status進(jìn)程可運(yùn)行狀態(tài)為R,不可中斷運(yùn)行為D(后續(xù)講解 top 時(shí)會(huì)詳細(xì)說(shuō)明)
top查看系統(tǒng)平均負(fù)載:
top - 13:09:42 up 888 days, 21:32, 8 users, load average: 19.95, 14.71, 14.01Tasks: 642 total, 2 running, 640 sleeping, 0 stopped, 0 zombie%Cpu0 : 37.5 us, 27.6 sy, 0.0 ni, 30.9 id, 0.0 wa, 0.0 hi, 3.6 si, 0.3 st%Cpu1 : 34.1 us, 31.5 sy, 0.0 ni, 34.1 id, 0.0 wa, 0.0 hi, 0.4 si, 0.0 st...KiB Mem : 14108016 total, 2919496 free, 6220236 used, 4968284 buff/cacheKiB Swap: 0 total, 0 free, 0 used. 6654506 avail Mem
這里的load average就表示系統(tǒng)最近 1 分鐘、5 分鐘、15 分鐘的系統(tǒng)瓶頸負(fù)載。
uptime查看系統(tǒng)瓶頸負(fù)載
[root /home/user]# uptime13:11:01 up 888 days, 21:33, 8 users, load average: 17.20, 14.85, 14.10
查看 CPU 核信息
系統(tǒng)平均負(fù)載和 CPU 核數(shù)密切相關(guān),我們可以通過(guò)以下命令查看當(dāng)前機(jī)器 CPU 信息:
lscpu查看 CPU 信息:
[root@Tencent-SNG /home/user_00]# lscpuArchitecture: x86_64CPU op-mode(s): 32-bit, 64-bitByte Order: Little EndianCPU(s): 8...L1d cache: 32KL1i cache: 32KL2 cache: 4096KNUMA node0 CPU(s): 0-7 // NUMA架構(gòu)信息
cat /proc/cpuinfo查看每個(gè) CPU 核的信息:
processor : 7 // 核編號(hào)7vendor_id : GenuineIntelcpu family : 6model : 6...
系統(tǒng)平均負(fù)載升高的原因
一般來(lái)說(shuō),系統(tǒng)平均負(fù)載升高意味著 CPU 使用率上升。但是他們沒(méi)有必然聯(lián)系,CPU 密集型計(jì)算任務(wù)較多一般系統(tǒng)平均負(fù)載會(huì)上升,但是如果 IO 密集型任務(wù)較多也會(huì)導(dǎo)致系統(tǒng)平均負(fù)載升高但是此時(shí)的 CPU 使用率不一定高,可能很低因?yàn)楹芏噙M(jìn)程都處于不可中斷狀態(tài),等待 CPU 調(diào)度也會(huì)升高系統(tǒng)平均負(fù)載。
所以假如我們系統(tǒng)平均負(fù)載很高,但是 CPU 使用率不是很高,則需要考慮是否系統(tǒng)遇到了 IO 瓶頸,應(yīng)該優(yōu)化 IO 讀寫速度。
所以系統(tǒng)是否遇到 CPU 瓶頸需要結(jié)合 CPU 使用率,系統(tǒng)瓶頸負(fù)載一起查看(當(dāng)然還有其他指標(biāo)需要對(duì)比查看,下面繼續(xù)講解)
案例問(wèn)題排查
stress是一個(gè)施加系統(tǒng)壓力和壓力測(cè)試系統(tǒng)的工具,我們可以使用stress工具壓測(cè)試 CPU,以便方便我們定位和排查 CPU 問(wèn)題。
yum install stress // 安裝stress工具stress 命令使用
// --cpu 8:8個(gè)進(jìn)程不停的執(zhí)行sqrt()計(jì)算操作// --io 4:4個(gè)進(jìn)程不同的執(zhí)行sync()io操作(刷盤)// --vm 2:2個(gè)進(jìn)程不停的執(zhí)行malloc()內(nèi)存申請(qǐng)操作// --vm-bytes 128M:限制1個(gè)執(zhí)行malloc的進(jìn)程申請(qǐng)內(nèi)存大小stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s
我們這里主要驗(yàn)證 CPU、IO、進(jìn)程數(shù)過(guò)多的問(wèn)題
CPU 問(wèn)題排查
使用stress -c 1模擬 CPU 高負(fù)載情況,然后使用如下命令觀察負(fù)載變化情況:
uptime:使用uptime查看此時(shí)系統(tǒng)負(fù)載:
# -d 參數(shù)表示高亮顯示變化的區(qū)域$ watch -d uptime... load average: 1.00, 0.75, 0.39
mpstat:使用mpstat -P ALL 1則可以查看每一秒的 CPU 每一核變化信息,整體和top類似,好處是可以把每一秒(自定義)的數(shù)據(jù)輸出方便觀察數(shù)據(jù)的變化,最終輸出平均數(shù)據(jù):
13:14:53 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle13:14:58 all 12.89 0.00 0.18 0.00 0.00 0.03 0.00 0.00 0.00 86.9113:14:58 0 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.0013:14:58 1 0.40 0.00 0.20 0.00 0.00 0.20 0.00 0.00 0.00 99.20
由以上輸出可以得出結(jié)論,當(dāng)前系統(tǒng)負(fù)載升高,并且其中 1 個(gè)核跑滿主要在執(zhí)行用戶態(tài)任務(wù),此時(shí)大多數(shù)屬于業(yè)務(wù)工作。所以此時(shí)需要查哪個(gè)進(jìn)程導(dǎo)致單核 CPU 跑滿:
pidstat:使用pidstat -u 1則是每隔 1 秒輸出當(dāng)前系統(tǒng)進(jìn)程、CPU 數(shù)據(jù):
13:18:00 UID PID %usr %system %guest %CPU CPU Command13:18:01 0 1 1.00 0.00 0.00 1.00 4 systemd13:18:01 0 3150617 100.00 0.00 0.00 100.00 0 stress...
top:當(dāng)然最方便的還是使用top命令查看負(fù)載情況:
top - 13:19:06 up 125 days, 20:01, 3 users, load average: 0.99, 0.63, 0.42Tasks: 223 total, 2 running, 221 sleeping, 0 stopped, 0 zombie%Cpu(s): 14.5 us, 0.3 sy, 0.0 ni, 85.1 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 stKiB Mem : 16166056 total, 3118532 free, 9550108 used, 3497416 buff/cacheKiB Swap: 0 total, 0 free, 0 used. 6447640 avail MemPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND3150617 root 20 0 10384 120 0 R 100.0 0.0 4:36.89 stress
此時(shí)可以看到是stress占用了很高的 CPU。
IO 問(wèn)題排查
我們使用stress -i 1來(lái)模擬 IO 瓶頸問(wèn)題,即死循環(huán)執(zhí)行 sync 刷盤操作:uptime:使用uptime查看此時(shí)系統(tǒng)負(fù)載:
$ watch -d uptime..., load average: 1.06, 0.58, 0.37
mpstat:查看此時(shí) IO 消耗,但是實(shí)際上我們發(fā)現(xiàn)這里 CPU 基本都消耗在了 sys 即系統(tǒng)消耗上。
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idleAverage: all 0.33 0.00 12.64 0.13 0.00 0.00 0.00 0.00 0.00 86.90Average: 0 0.00 0.00 99.00 1.00 0.00 0.00 0.00 0.00 0.00 0.00Average: 1 0.00 0.00 0.33 0.00 0.00 0.00 0.00 0.00 0.00 99.67
IO 無(wú)法升高的問(wèn)題:
iowait 無(wú)法升高的問(wèn)題,是因?yàn)榘咐?stress 使用的是 sync()系統(tǒng)調(diào)用,它的作用是刷新緩沖區(qū)內(nèi)存到磁盤中。對(duì)于新安裝的虛擬機(jī),緩沖區(qū)可能比較小,無(wú)法產(chǎn)生大的 IO 壓力,這樣大部分就都是系統(tǒng)調(diào)用的消耗了。所以,你會(huì)看到只有系統(tǒng) CPU 使用率升高。解決方法是使用 stress 的下一代 stress-ng,它支持更豐富的選項(xiàng),比如stress-ng -i 1 --hdd 1 --timeout 600(--hdd 表示讀寫臨時(shí)文件)。
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idleAverage: all 0.25 0.00 0.44 26.22 0.00 0.00 0.00 0.00 0.00 73.09Average: 0 0.00 0.00 1.02 98.98 0.00 0.00 0.00 0.00 0.00 0.00
pidstat:同上(略)
可以看出 CPU 的 IO 升高導(dǎo)致系統(tǒng)平均負(fù)載升高。我們使用pidstat查找具體是哪個(gè)進(jìn)程導(dǎo)致 IO 升高的。
top:這里使用 top 依舊是最方面的查看綜合參數(shù),可以得出stress是導(dǎo)致 IO 升高的元兇。
pidstat 沒(méi)有 iowait 選項(xiàng):可能是 CentOS 默認(rèn)的sysstat太老導(dǎo)致,需要升級(jí)到 11.5.5 之后的版本才可用。
進(jìn)程數(shù)過(guò)多問(wèn)題排查
進(jìn)程數(shù)過(guò)多這個(gè)問(wèn)題比較特殊,如果系統(tǒng)運(yùn)行了很多進(jìn)程超出了 CPU 運(yùn)行能,就會(huì)出現(xiàn)等待 CPU 的進(jìn)程。使用stress -c 24來(lái)模擬執(zhí)行 24 個(gè)進(jìn)程(我的 CPU 是 8 核)uptime:使用uptime查看此時(shí)系統(tǒng)負(fù)載:
$ watch -d uptime..., load average: 18.50, 7.13, 2.84
mpstat:同上(略)
pidstat:同上(略)
可以觀察到此時(shí)的系統(tǒng)處理嚴(yán)重過(guò)載的狀態(tài),平均負(fù)載高達(dá) 18.50。
top:我們還可以使用top命令查看此時(shí)Running狀態(tài)的進(jìn)程數(shù),這個(gè)數(shù)量很多就表示系統(tǒng)正在運(yùn)行、等待運(yùn)行的進(jìn)程過(guò)多。
總結(jié)
通過(guò)以上問(wèn)題現(xiàn)象及解決思路可以總結(jié)出:
平均負(fù)載高有可能是 CPU 密集型進(jìn)程導(dǎo)致的 平均負(fù)載高并不一定代表 CPU 使用率高,還有可能是 I/O 更繁忙了 當(dāng)發(fā)現(xiàn)負(fù)載高的時(shí)候,你可以使用 mpstat、pidstat 等工具,輔助分析負(fù)載的來(lái)源
總結(jié)工具:mpstat、pidstat、top和uptime
CPU 上下文切換
CPU 上下文:CPU 執(zhí)行每個(gè)任務(wù)都需要知道任務(wù)從哪里加載、又從哪里開始運(yùn)行,也就是說(shuō),需要系統(tǒng)事先幫它設(shè)置好 CPU 寄存器和程序計(jì)數(shù)器(Program Counter,PC)包括 CPU 寄存器在內(nèi)都被稱為 CPU 上下文。
CPU 上下文切換:CPU 上下文切換,就是先把前一個(gè)任務(wù)的 CPU 上下文(也就是 CPU 寄存器和程序計(jì)數(shù)器)保存起來(lái),然后加載新任務(wù)的上下文到這些寄存器和程序計(jì)數(shù)器,最后再跳轉(zhuǎn)到程序計(jì)數(shù)器所指的新位置,運(yùn)行新任務(wù)。
CPU 上下文切換:分為進(jìn)程上下文切換、線程上下文切換以及中斷上下文切換。
進(jìn)程上下文切換
從用戶態(tài)切換到內(nèi)核態(tài)需要通過(guò)系統(tǒng)調(diào)用來(lái)完成,這里就會(huì)發(fā)生進(jìn)程上下文切換(特權(quán)模式切換),當(dāng)切換回用戶態(tài)同樣發(fā)生上下文切換。
一般每次上下文切換都需要幾十納秒到數(shù)微秒的 CPU 時(shí)間,如果切換較多還是很容易導(dǎo)致 CPU 時(shí)間的浪費(fèi)在寄存器、內(nèi)核棧以及虛擬內(nèi)存等資源的保存和恢復(fù)上,這里同樣會(huì)導(dǎo)致系統(tǒng)平均負(fù)載升高。
Linux 為每個(gè) CPU 維護(hù)一個(gè)就緒隊(duì)列,將 R 狀態(tài)進(jìn)程按照優(yōu)先級(jí)和等待 CPU 時(shí)間排序,選擇最需要的 CPU 進(jìn)程執(zhí)行。這里運(yùn)行進(jìn)程就涉及了進(jìn)程上下文切換的時(shí)機(jī):
進(jìn)程時(shí)間片耗盡、。 進(jìn)程在系統(tǒng)資源不足(內(nèi)存不足)。 進(jìn)程主動(dòng) sleep。有優(yōu)先級(jí)更高的進(jìn)程執(zhí)行。 硬中斷發(fā)生。
線程上下文切換
線程和進(jìn)程:
當(dāng)進(jìn)程只有一個(gè)線程時(shí),可以認(rèn)為進(jìn)程就等于線程。 當(dāng)進(jìn)程擁有多個(gè)線程時(shí),這些線程會(huì)共享相同的虛擬內(nèi)存和全局變量等資源。這些資源在上下文切換時(shí)是不需要修改的。 線程也有自己的私有數(shù)據(jù),比如棧和寄存器等,這些在上下文切換時(shí)也是需要保存的。
所以線程上下文切換包括了 2 種情況:
不同進(jìn)程的線程,這種情況等同于進(jìn)程切換。 通進(jìn)程的線程切換,只需要切換線程私有數(shù)據(jù)、寄存器等不共享數(shù)據(jù)。
中斷上下文切換
中斷處理會(huì)打斷進(jìn)程的正常調(diào)度和執(zhí)行,轉(zhuǎn)而調(diào)用中斷處理程序,響應(yīng)設(shè)備事件。而在打斷其他進(jìn)程時(shí),就需要將進(jìn)程當(dāng)前的狀態(tài)保存下來(lái),這樣在中斷結(jié)束后,進(jìn)程仍然可以從原來(lái)的狀態(tài)恢復(fù)運(yùn)行。
對(duì)同一個(gè) CPU 來(lái)說(shuō),中斷處理比進(jìn)程擁有更高的優(yōu)先級(jí),所以中斷上下文切換并不會(huì)與進(jìn)程上下文切換同時(shí)發(fā)生。由于中斷會(huì)打斷正常進(jìn)程的調(diào)度和執(zhí)行,所以大部分中斷處理程序都短小精悍,以便盡可能快的執(zhí)行結(jié)束。
查看系統(tǒng)上下文切換
vmstat:工具可以查看系統(tǒng)的內(nèi)存、CPU 上下文切換以及中斷次數(shù):
// 每隔1秒輸出$ vmstat 1procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st3 0 0 157256 3241604 5144444 0 0 20 0 26503 33960 18 7 75 0 017 0 0 159984 3241708 5144452 0 0 12 0 29560 37696 15 10 75 0 06 0 0 162044 3241816 5144456 0 0 8 120 30683 38861 17 10 73 0 0
cs:則為每秒的上下文切換次數(shù)。
in:則為每秒的中斷次數(shù)。
r:就緒隊(duì)列長(zhǎng)度,正在運(yùn)行或等待 CPU 的進(jìn)程。
b:不可中斷睡眠狀態(tài)的進(jìn)程數(shù),例如正在和硬件交互。
pidstat:使用pidstat -w選項(xiàng)查看具體進(jìn)程的上下文切換次數(shù):
$ pidstat -w -p 3217281 110:19:13 UID PID cswch/s nvcswch/s Command10:19:14 0 3217281 0.00 18.00 stress10:19:15 0 3217281 0.00 18.00 stress10:19:16 0 3217281 0.00 28.71 stress
其中cswch/s和nvcswch/s表示自愿上下文切換和非自愿上下文切換。
自愿上下文切換:是指進(jìn)程無(wú)法獲取所需資源,導(dǎo)致的上下文切換。比如說(shuō), I/O、內(nèi)存等系統(tǒng)資源不足時(shí),就會(huì)發(fā)生自愿上下文切換。
非自愿上下文切換:則是指進(jìn)程由于時(shí)間片已到等原因,被系統(tǒng)強(qiáng)制調(diào)度,進(jìn)而發(fā)生的上下文切換。比如說(shuō),大量進(jìn)程都在爭(zhēng)搶 CPU 時(shí),就容易發(fā)生非自愿上下文切換
案例問(wèn)題排查
這里我們使用sysbench工具模擬上下文切換問(wèn)題。
先使用vmstat 1查看當(dāng)前上下文切換信息:
$ vmstat 1procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st2 0 0 514540 3364828 5323356 0 0 10 16 0 0 4 1 95 0 01 0 0 514316 3364932 5323408 0 0 8 0 27900 34809 17 10 73 0 01 0 0 507036 3365008 5323500 0 0 8 0 23750 30058 19 9 72 0 0
然后使用sysbench --threads=64 --max-time=300 threads run模擬 64 個(gè)線程執(zhí)行任務(wù),此時(shí)我們?cè)俅?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;font-family: "Microsoft YaHei";">vmstat 1查看上下文切換信息:
$ vmstat 1procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st2 0 0 318792 3385728 5474272 0 0 10 16 0 0 4 1 95 0 01 0 0 307492 3385756 5474316 0 0 8 0 15710 20569 20 8 72 0 01 0 0 330032 3385824 5474376 0 0 8 16 21573 26844 19 9 72 0 02 0 0 321264 3385876 5474396 0 0 12 0 21218 26100 20 7 73 0 06 0 0 320172 3385932 5474440 0 0 12 0 19363 23969 19 8 73 0 014 0 0 323488 3385980 5474828 0 0 64 788 111647 3745536 24 61 15 0 014 0 0 323576 3386028 5474856 0 0 8 0 118383 4317546 25 64 11 0 016 0 0 315560 3386100 5475056 0 0 8 16 115253 4553099 22 68 9 0 0
我們可以明顯的觀察到:
當(dāng)前 cs、in 此時(shí)劇增。 sy+us 的 CPU 占用超過(guò) 90%。 r 就緒隊(duì)列長(zhǎng)度達(dá)到 16 個(gè)超過(guò)了 CPU 核心數(shù) 8 個(gè)。
分析 cs 上下文切換問(wèn)題
我們使用pidstat查看當(dāng)前 CPU 信息和具體的進(jìn)程上下文切換信息:
// -w表示查看進(jìn)程切換信息,-u查看CPU信息,-t查看線程切換信息$ pidstat -w -u -t 110:35:01 UID PID %usr %system %guest %CPU CPU Command10:35:02 0 3383478 67.33 100.00 0.00 100.00 1 sysbench10:35:01 UID PID cswch/s nvcswch/s Command10:45:39 0 3509357 - 1.00 0.00 kworker/2:210:45:39 0 - 3509357 1.00 0.00 |__kworker/2:210:45:39 0 - 3509702 38478.00 45587.00 |__sysbench10:45:39 0 - 3509703 39913.00 41565.00 |__sysbench
所以我們可以看到大量的sysbench線程存在很多的上下文切換。
分析 in 中斷問(wèn)題
我們可以查看系統(tǒng)的watch -d cat /proc/softirqs以及watch -d cat /proc/interrupts來(lái)查看系統(tǒng)的軟中斷和硬中斷(內(nèi)核中斷)。我們這里主要觀察/proc/interrupts即可。
$ watch -d cat /proc/interruptsRES: 900997016 912023527 904378994 902594579 899800739 897500263 895024925 895452133 Rescheduling interrupts
這里明顯看出重調(diào)度中斷(RES)增多,這個(gè)中斷表示喚醒空閑狀態(tài) CPU 來(lái)調(diào)度新任務(wù)執(zhí)行,
總結(jié)
自愿上下文切換變多了,說(shuō)明進(jìn)程都在等待資源,有可能發(fā)生了 I/O 等其他問(wèn)題。 非自愿上下文切換變多了,說(shuō)明進(jìn)程都在被強(qiáng)制調(diào)度,也就是都在爭(zhēng)搶 CPU,說(shuō)明 CPU 的確成了瓶頸。 中斷次數(shù)變多了,說(shuō)明 CPU 被中斷處理程序占用,還需要通過(guò)查看 /proc/interrupts文件來(lái)分析具體的中斷類型。
CPU 使用率
除了系統(tǒng)負(fù)載、上下文切換信息,最直觀的 CPU 問(wèn)題指標(biāo)就是 CPU 使用率信息。Linux 通過(guò)/proc虛擬文件系統(tǒng)向用戶控件提供系統(tǒng)內(nèi)部狀態(tài)信息,其中/proc/stat則是 CPU 和任務(wù)信息統(tǒng)計(jì)。
$ cat /proc/stat | grep cpucpu 6392076667 1160 3371352191 52468445328 3266914 37086 36028236 20721765 0 0cpu0 889532957 175 493755012 6424323330 2180394 37079 17095455 3852990 0 0...
這里每一列的含義如下:
user(通??s寫為 us),代表用戶態(tài) CPU 時(shí)間。注意,它不包括下面的 nice 時(shí)間,但包括了 guest 時(shí)間。 nice(通??s寫為 ni),代表低優(yōu)先級(jí)用戶態(tài) CPU 時(shí)間,也就是進(jìn)程的 nice 值被調(diào)整為 1-19 之間時(shí)的 CPU 時(shí)間。這里注意,nice 可取值范圍是 -20 到 19,數(shù)值越大,優(yōu)先級(jí)反而越低。 system(通??s寫為 sys),代表內(nèi)核態(tài) CPU 時(shí)間。 idle(通??s寫為 id),代表空閑時(shí)間。注意,它不包括等待 I/O 的時(shí)間(iowait)。 iowait(通常縮寫為 wa),代表等待 I/O 的 CPU 時(shí)間。 irq(通??s寫為 hi),代表處理硬中斷的 CPU 時(shí)間。 softirq(通??s寫為 si),代表處理軟中斷的 CPU 時(shí)間。 steal(通??s寫為 st),代表當(dāng)系統(tǒng)運(yùn)行在虛擬機(jī)中的時(shí)候,被其他虛擬機(jī)占用的 CPU 時(shí)間。 guest(通??s寫為 guest),代表通過(guò)虛擬化運(yùn)行其他操作系統(tǒng)的時(shí)間,也就是運(yùn)行虛擬機(jī)的 CPU 時(shí)間。 guest_nice(通常縮寫為 gnice),代表以低優(yōu)先級(jí)運(yùn)行虛擬機(jī)的時(shí)間。
這里我們可以使用top、ps、pidstat等工具方便的查詢這些數(shù)據(jù),可以很方便的看到 CPU 使用率很高的進(jìn)程,這里我們可以通過(guò)這些工具初步定為,但是具體的問(wèn)題原因還需要其他方法繼續(xù)查找。
這里我們可以使用perf top方便查看熱點(diǎn)數(shù)據(jù),也可以使用perf record可以將當(dāng)前數(shù)據(jù)保存起來(lái)方便后續(xù)使用perf report查看。
CPU 使用率問(wèn)題排查
這里總結(jié)一下 CPU 使用率問(wèn)題及排查思路:
用戶 CPU 和 Nice CPU 高,說(shuō)明用戶態(tài)進(jìn)程占用了較多的 CPU,所以應(yīng)該著重排查進(jìn)程的性能問(wèn)題。 系統(tǒng) CPU 高,說(shuō)明內(nèi)核態(tài)占用了較多的 CPU,所以應(yīng)該著重排查內(nèi)核線程或者系統(tǒng)調(diào)用的性能問(wèn)題。 I/O 等待 CPU 高,說(shuō)明等待 I/O 的時(shí)間比較長(zhǎng),所以應(yīng)該著重排查系統(tǒng)存儲(chǔ)是不是出現(xiàn)了 I/O 問(wèn)題。 軟中斷和硬中斷高,說(shuō)明軟中斷或硬中斷的處理程序占用了較多的 CPU,所以應(yīng)該著重排查內(nèi)核中的中斷服務(wù)程序。
CPU 問(wèn)題排查套路
CPU 使用率
CPU 使用率主要包含以下幾個(gè)方面:
用戶 CPU 使用率,包括用戶態(tài) CPU 使用率(user)和低優(yōu)先級(jí)用戶態(tài) CPU 使用率(nice),表示 CPU 在用戶態(tài)運(yùn)行的時(shí)間百分比。用戶 CPU 使用率高,通常說(shuō)明有應(yīng)用程序比較繁忙。 系統(tǒng) CPU 使用率,表示 CPU 在內(nèi)核態(tài)運(yùn)行的時(shí)間百分比(不包括中斷)。系統(tǒng) CPU 使用率高,說(shuō)明內(nèi)核比較繁忙。 等待 I/O 的 CPU 使用率,通常也稱為 iowait,表示等待 I/O 的時(shí)間百分比。iowait 高,通常說(shuō)明系統(tǒng)與硬件設(shè)備的 I/O 交互時(shí)間比較長(zhǎng)。 軟中斷和硬中斷的 CPU 使用率,分別表示內(nèi)核調(diào)用軟中斷處理程序、硬中斷處理程序的時(shí)間百分比。它們的使用率高,通常說(shuō)明系統(tǒng)發(fā)生了大量的中斷。 除在虛擬化環(huán)境中會(huì)用到的竊取 CPU 使用率(steal)和客戶 CPU 使用率(guest),分別表示被其他虛擬機(jī)占用的 CPU 時(shí)間百分比,和運(yùn)行客戶虛擬機(jī)的 CPU 時(shí)間百分比。
平均負(fù)載
反應(yīng)了系統(tǒng)的整體負(fù)載情況,可以查看過(guò)去 1 分鐘、過(guò)去 5 分鐘和過(guò)去 15 分鐘的平均負(fù)載。
上下文切換
上下文切換主要關(guān)注 2 項(xiàng)指標(biāo):
無(wú)法獲取資源而導(dǎo)致的自愿上下文切換。 被系統(tǒng)強(qiáng)制調(diào)度導(dǎo)致的非自愿上下文切換。
CPU 緩存命中率
CPU 的訪問(wèn)速度遠(yuǎn)大于內(nèi)存訪問(wèn),這樣在 CPU 訪問(wèn)內(nèi)存時(shí)不可避免的要等待內(nèi)存響應(yīng)。為了協(xié)調(diào) 2 者的速度差距出現(xiàn)了 CPU 緩存(多級(jí)緩存)。如果 CPU 緩存命中率越高則性能會(huì)更好,我們可以使用以下工具查看 CPU 緩存命中率,工具地址、項(xiàng)目地址 perf-tools
# ./cachestat -tCounting cache functions... Output every 1 seconds.TIME HITS MISSES DIRTIES RATIO BUFFERS_MB CACHE_MB08:28:57 415 0 0 100.0% 1 19108:28:58 411 0 0 100.0% 1 19108:28:59 362 97 0 78.9% 0 808:29:00 411 0 0 100.0% 0 908:29:01 775 20489 0 3.6% 0 8908:29:02 411 0 0 100.0% 0 8908:29:03 6069 0 0 100.0% 0 8908:29:04 15249 0 0 100.0% 0 8908:29:05 411 0 0 100.0% 0 8908:29:06 411 0 0 100.0% 0 8908:29:07 411 0 3 100.0% 0 89[...]
總結(jié)
通過(guò)性能指標(biāo)查工具(CPU 相關(guān))
| 性能指標(biāo) | 工具 | 說(shuō)明 |
|---|---|---|
| 平均負(fù)載 | uptime top | uptime 簡(jiǎn)單展示最近一段時(shí)間的平均負(fù)載 top 展示更多指標(biāo) |
| CPU 使用率 | vmstat mpstat top sar /proc/stat | top、vmstat、mpstat 只可以動(dòng)態(tài)查看當(dāng)前,而 sar 可以查看歷史 /proc/stat 是其他性能工具的數(shù)據(jù)來(lái)源 |
| 進(jìn)程 CPU 使用率 | top pidstat ps htop atop | top、ps 可以以排序方式展示進(jìn)程 CPU、pidstat 不可排序展示 htop、atop 則以不同顏色展示各類數(shù)據(jù)更直觀 |
| 系統(tǒng)上下文切換 | vmstat | 展示上下文切換此時(shí)、運(yùn)行狀態(tài)、不可中斷狀態(tài)進(jìn)程數(shù)量 |
| 進(jìn)程上下文切換 | pidstat | 展示項(xiàng)很多,包括進(jìn)程上下文切換信息 |
| 軟中斷 | top /proc/softirqs mpstat | top 可查看軟中斷 CPU 使用率 /proc/softirqs 和 mpstat 則可以查看每個(gè) CPU 上的累計(jì)信息 |
| 硬中斷 | vmstat /proc/interrupts | vmstat 查看總中斷次數(shù)信息 /proc/interrupts 查看各種中斷在每個(gè) CPU 核心上的累計(jì)信息 |
| 網(wǎng)絡(luò) | dstat sar tcpdump | dstat、sar 較詳細(xì)的展示出總的網(wǎng)絡(luò)收發(fā)情況 tcpdump 提供動(dòng)態(tài)抓取數(shù)據(jù)包的能力 |
| IO | dstat、sar | 2 者都提供了詳細(xì)的 IO 整體情況 |
| CPU 信息 | /proc/cpuinfo lscpu | 都可以查看 CPU 信息 |
| 系統(tǒng)分析 | perf execsnoop | perf 分析各種內(nèi)核函數(shù)調(diào)用、熱點(diǎn)函數(shù)信息 execsnoop 監(jiān)控短時(shí)進(jìn)程 |
根據(jù)工具查性能指標(biāo)(CPU 相關(guān))
| 性能工具 | CPU 性能指標(biāo) |
|---|---|
| uptime | 5、10、15 分鐘內(nèi)的平均負(fù)載展示 |
| top | 平均負(fù)載、運(yùn)行隊(duì)列、CPU 各項(xiàng)使用率、進(jìn)程狀態(tài)和 CPU 使用率 |
| htop | top 增強(qiáng)版,以不同顏色區(qū)分不同類型進(jìn)程,展示更直觀 |
| atop | CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)資源全訪問(wèn)監(jiān)控,十分齊全 |
| vmstat | 系統(tǒng)整體 CPU 使用率、上下文切換次數(shù)、中斷次數(shù),還包括處于運(yùn)行(r)和不可中斷狀態(tài)(b)的進(jìn)程數(shù)量 |
| pidstat | 進(jìn)程、線程(-t)的每個(gè) CPU 占用信息,中斷上下文切換次數(shù) |
| /proc/softirqs | 展示每個(gè) CPU 上的軟中斷類型及次數(shù) |
| /proc/inerrupts | 展示每個(gè) CPU 上的硬中斷類型及次數(shù) |
| ps | 每個(gè)進(jìn)程的狀態(tài)和 CPU 使用率 |
| pstree | 進(jìn)程的父子關(guān)系展示 |
| dstat | 系統(tǒng)整體 CPU 使用率(以及相關(guān) IO、網(wǎng)絡(luò)信息) |
| sar | 系統(tǒng)整體 CPU 使用率,以及使用率歷史信息 |
| strace | 跟蹤進(jìn)程的系統(tǒng)調(diào)用 |
| perf | CPU 性能事件分析,例如:函數(shù)調(diào)用鏈、CPU 緩存命中率、CPU 調(diào)度等 |
| execsnoop | 短時(shí)進(jìn)程分析 |
CPU 問(wèn)題排查方向
有了以上性能工具,在實(shí)際遇到問(wèn)題時(shí)我們并不可能全部性能工具跑一遍,這樣效率也太低了,所以這里可以先運(yùn)行幾個(gè)常用的工具 top、vmstat、pidstat 分析系統(tǒng)大概的運(yùn)行情況然后在具體定位原因。
top 系統(tǒng)CPU => vmstat 上下文切換次數(shù) => pidstat 非自愿上下文切換次數(shù) => 各類進(jìn)程分析工具(perf strace ps execsnoop pstack)top 用戶CPU => pidstat 用戶CPU => 一般是CPU計(jì)算型任務(wù)top 僵尸進(jìn)程 => 各類進(jìn)程分析工具(perf strace ps execsnoop pstack)top 平均負(fù)載 => vmstat 運(yùn)行狀態(tài)進(jìn)程數(shù) => pidstat 用戶CPU => 各類進(jìn)程分析工具(perf strace ps execsnoop pstack)top 等待IO CPU => vmstat 不可中斷狀態(tài)進(jìn)程數(shù) => IO分析工具(dstat、sar -d)top 硬中斷 => vmstat 中斷次數(shù) => 查看具體中斷類型(/proc/interrupts)top 軟中斷 => 查看具體中斷類型(/proc/softirqs) => 網(wǎng)絡(luò)分析工具(sar -n、tcpdump) 或者 SCHED(pidstat 非自愿上下文切換)
CPU 問(wèn)題優(yōu)化方向
性能優(yōu)化往往是多方面的,CPU、內(nèi)存、網(wǎng)絡(luò)等都是有關(guān)聯(lián)的,這里暫且給出 CPU 優(yōu)化的思路,以供參考。
程序優(yōu)化
基本優(yōu)化:程序邏輯的優(yōu)化比如減少循環(huán)次數(shù)、減少內(nèi)存分配,減少遞歸等等。 編譯器優(yōu)化:開啟編譯器優(yōu)化選項(xiàng)例如 gcc -O2對(duì)程序代碼優(yōu)化。算法優(yōu)化:降低蘇研發(fā)復(fù)雜度,例如使用 nlogn的排序算法,使用logn的查找算法等。異步處理:例如把輪詢改為通知方式 多線程代替多進(jìn)程:某些場(chǎng)景下多線程可以代替多進(jìn)程,因?yàn)樯舷挛那袚Q成本較低 緩存:包括多級(jí)緩存的使用(略)加快數(shù)據(jù)訪問(wèn)
系統(tǒng)優(yōu)化
CPU 綁定:綁定到一個(gè)或多個(gè) CPU 上,可以提高 CPU 緩存命中率,減少跨 CPU 調(diào)度帶來(lái)的上下文切換問(wèn)題 CPU 獨(dú)占:跟 CPU 綁定類似,進(jìn)一步將 CPU 分組,并通過(guò) CPU 親和性機(jī)制為其分配進(jìn)程。 優(yōu)先級(jí)調(diào)整:使用 nice 調(diào)整進(jìn)程的優(yōu)先級(jí),適當(dāng)降低非核心應(yīng)用的優(yōu)先級(jí),增高核心應(yīng)用的優(yōu)先級(jí),可以確保核心應(yīng)用得到優(yōu)先處理。 為進(jìn)程設(shè)置資源限制:使用 Linux cgroups 來(lái)設(shè)置進(jìn)程的 CPU 使用上限,可以防止由于某個(gè)應(yīng)用自身的問(wèn)題,而耗盡系統(tǒng)資源。 NUMA 優(yōu)化:支持 NUMA 的處理器會(huì)被劃分為多個(gè) Node,每個(gè) Node 有本地的內(nèi)存空間,這樣 CPU 可以直接訪問(wèn)本地空間內(nèi)存。 中斷負(fù)載均衡:無(wú)論是軟中斷還是硬中斷,它們的中斷處理程序都可能會(huì)耗費(fèi)大量的 CPU。開啟 irqbalance 服務(wù)或者配置 smp_affinity,就可以把中斷處理過(guò)程自動(dòng)負(fù)載均衡到多個(gè) CPU 上。
參考
極客時(shí)間:Linux 性能優(yōu)化實(shí)戰(zhàn)
