2.2 CPU 上下文切换是什么意思?(下)
怎么查看系統的上下文切換情況
過多的上下文切換,會把 CPU 時間消耗在寄存器、內核棧以及虛擬內存等數據的保存和恢復上,縮短進程真正運行的時間,成了系統性能大幅下降的一個 元兇。
使用 vmstat 這個工具,來查詢系統的上下文切換情況。
vmstat 是一個常用的系統性能分析工具,主要用來分析系統的內存使用情況,也常用來分析 CPU 上下文切換和中斷的次數。
vmstat 的使用示例:
???? vmstat 只給出了系統總體的上下文切換情況,要想查看每個進程的詳細情況,就需要使用我們前面提到過的 pidstat 了。給它加上 -w 選項,你就可以查看每個進程上下文切換的情況了。
每隔 5 秒輸出 1 組數據 [root@doit ~]# pidstat -w 5 Linux 4.20.0-1.el7.elrepo.x86_64 (doit) 07/12/2019 _x86_64_ (2 CPU)04:28:40 PM UID PID cswch/s nvcswch/s Command04:28:45 PM 0 9 0.20 0.00 ksoftirqd/004:28:45 PM 0 10 2.00 0.00 rcu_sched04:28:45 PM 0 11 0.40 0.00 migration/004:28:45 PM 0 15 0.40 0.00 migration/104:28:45 PM 0 27 0.20 0.00 khugepaged04:28:45 PM 0 3086 0.20 0.00 haveged04:28:45 PM 0 3104 9.98 0.00 qemu-ga04:28:45 PM 0 3492 1.00 0.00 httpd04:28:45 PM 0 6094 0.40 0.00 python04:28:45 PM 0 29541 5.39 0.00 kworker/1:0-events_power_efficient04:28:45 PM 0 29590 1.40 0.00 kworker/0:1-events04:28:45 PM 0 29716 0.20 0.20 pidstat一個是 cswch ,表示每秒自愿上下文切換(voluntary context switches)的次數,另一個則是 nvcswch ,表示每秒非自愿上下文切換(non voluntary context switches)的次數。所謂自愿上下文切換,是指進程無法獲取所需資源,導致的上下文切換。比如說, I/O、內存等系統資源不足時,就會發生自愿上下文切換。
而非自愿上下文切換,則是指進程由于時間片已到等原因,被系統強制調度,進而發生的上下文切換。比如說,大量進程都在爭搶 CPU 時,就容易發生非自愿上下文切換。
案例分析
上下文切換頻率是多少次才算正常呢?
sysbench? 是一個多線程的基準測試工具,一般用來評估不同系統參數下的數據庫負載情況。當然,在這次案例中,我們只把它當成一個異常進程來看,作用是模擬上下文切換過多的問題。
預先安裝 sysbench 和 sysstat 包,如 apt install sysbench sysstat
操作和分析
首先,在第一個終端里運行 sysbench ,模擬系統多線程調度的瓶頸:
# 以 10 個線程運行 5 分鐘的基準測試,模擬多線程切換的問題 [root@doit ~]# sysbench --threads=10 --max-time=300 threads run WARNING: --max-time is deprecated, use --time instead sysbench 1.0.17 (using system LuaJIT 2.0.4)Running the test with following options: Number of threads: 10 Initializing random number generator from current timeInitializing worker threads...Threads started!
在第二個終端運行 vmstat ,觀察上下文切換情況:
綜合這幾個指標,我們可以知道,系統的就緒隊列過長,也就是正在運行和等待 CPU 的進程數過多,導致了大量的上下文切換,而上下文切換又導致了系統 CPU 的占用率升高。
那么到底是什么進程導致了這些問題呢?
在第三個終端再用 pidstat 來看一下, CPU 和進程上下文切換的情況
# 每隔 1 秒輸出 1 組數據-w 參數表示輸出進程切換指標,而 -u 參數則表示輸出 CPU 使用指標[root@doit ~]# pidstat -w -u 1Linux 4.20.0-1.el7.elrepo.x86_64 (doit) 07/12/2019 _x86_64_ (2 CPU)04:38:35 PM UID PID %usr %system %guest %wait %CPU CPU Command04:38:36 PM 0 29730 33.00 167.00 0.00 0.00 200.00 0 sysbench04:38:35 PM UID PID cswch/s nvcswch/s Command04:38:36 PM 0 10 3.00 0.00 rcu_sched04:38:36 PM 0 16 1.00 0.00 ksoftirqd/104:38:36 PM 0 3104 10.00 0.00 qemu-ga04:38:36 PM 0 3492 1.00 0.00 httpd04:38:36 PM 0 29541 14.00 0.00 kworker/1:0-events_power_efficient04:38:36 PM 0 29590 2.00 0.00 kworker/0:1-mm_percpu_wq04:38:36 PM 0 29640 1.00 0.00 sshd04:38:36 PM 0 29714 1.00 0.00 kworker/u4:0-events_unbound04:38:36 PM 0 29742 1.00 0.00 pidstat 從 pidstat 的輸出你可以發現,CPU 使用率的升高果然是 sysbench 導致的,它的 CPU 使用率已經達到了 200%。但上下文切換則是來自其他進程,自愿上下文切換頻率最高的內核線程 kworker。pidstat 輸出的上下文切換次數,加起來也就幾百,比 vmstat 的 139 萬明顯小了太多。這是怎么回事呢?難道是工具本身出了錯嗎?
pidstat 默認顯示進程的指標數據,加上 -t 參數后, 才會輸出線程的指標。
[root@doit ~]# pidstat -wt 1 Linux 4.20.0-1.el7.elrepo.x86_64 (doit) 07/12/2019 _x86_64_ (2 CPU)04:45:02 PM UID TGID TID cswch/s nvcswch/s Command04:45:03 PM 0 9 - 2.91 0.00 ksoftirqd/004:45:03 PM 0 - 9 2.91 0.00 |__ksoftirqd/004:45:03 PM 0 10 - 10.68 0.00 rcu_sched04:45:03 PM 0 - 10 10.68 0.00 |__rcu_sched04:45:03 PM 0 16 - 0.97 0.00 ksoftirqd/104:45:03 PM 0 - 16 0.97 0.00 |__ksoftirqd/104:45:03 PM 0 3104 - 9.71 0.00 qemu-ga04:45:03 PM 0 - 3104 9.71 0.00 |__qemu-ga04:45:03 PM 0 - 3820 0.97 0.00 |__tuned04:45:03 PM 0 6094 - 0.97 0.00 python04:45:03 PM 0 - 6094 0.97 0.00 |__python04:45:03 PM 0 - 14238 0.97 0.00 |__node04:45:03 PM 0 29590 - 1.94 0.00 kworker/0:1-mm_percpu_wq04:45:03 PM 0 - 29590 1.94 0.00 |__kworker/0:1-mm_percpu_wq04:45:03 PM 0 - 29768 20572.82 100301.94 |__sysbench04:45:03 PM 0 - 29769 18718.45 110695.15 |__sysbench04:45:03 PM 0 - 29770 22306.80 104282.52 |__sysbench04:45:03 PM 0 - 29771 26055.34 86372.82 |__sysbench04:45:03 PM 0 - 29772 20498.06 102583.50 |__sysbench04:45:03 PM 0 - 29773 14956.31 81900.00 |__sysbench04:45:03 PM 0 - 29774 29092.23 112430.10 |__sysbench04:45:03 PM 0 - 29775 24825.24 110958.25 |__sysbench04:45:03 PM 0 - 29776 23862.14 95394.17 |__sysbench04:45:03 PM 0 - 29777 21125.24 87931.07 |__sysbench04:45:03 PM 0 29780 - 12.62 0.00 kworker/1:1-events_power_efficient04:45:03 PM 0 - 29780 12.62 0.00 |__kworker/1:1-events_power_efficient04:45:03 PM 0 29783 - 0.97 1.94 pidstat04:45:03 PM 0 - 29783 0.97 1.94 |__pidstat? 雖然 sysbench 進程(也就是主線程)的上下文切換次數看起來并不多,但它的子線程的上下文切換次數卻有很多。看來,上下文切換罪魁禍首,還是過多的sysbench 線程。
?? 在觀察系統指標時,除了上下文切換頻率驟然升高,還有一個指標也有很大的變化。是的,正是中斷次數。中斷次數也上升到了 1 萬,但到底是什么類型的中斷上升了,現在還不清楚。接下來繼續抽絲剝繭找源頭。既然是中斷,我們都知道,它只發生在內核態,而 pidstat 只是一個進程的性能分析工具,并不提供任何關于中斷的詳細信息,怎樣才能知道中斷發生的類型呢?
沒錯,那就是從 /proc/interrupts 這個只讀文件中讀取。/proc 實際上是 Linux 的一個虛擬文件系統,用于內核空間與用戶空間之間的通信。/proc/interrupts? 就是這種通信機制的一部分,提供了一個只讀的中斷使用情況。
[root@doit ~]# watch -d cat /proc/interruptsEvery 2.0s: cat /proc/interrupts Fri Jul 12 16:49:08 2019CPU0 CPU1LOC: 83008310 107586288 Local timer interruptsSPU: 0 0 Spurious interruptsPMI: 0 0 Performance monitoring interruptsIWI: 0 1 IRQ work interruptsRTR: 0 0 APIC ICR read retriesRES: 9169892 7079828 Rescheduling interrupts???? 觀察一段時間,你可以發現,變化速度最快的是重調度中斷(RES),這個中斷類型表示,喚醒空閑狀態的 CPU 來調度新的任務運行。這是多處理器系統(SMP)中,調度器用來分散任務到不同 CPU 的機制,通常也被稱為處理器間中斷(Inter-Processor Interrupts,IPI)。所以,這里的中斷升高還是因為過多任務的調度問題,跟前面上下文切換次數的分析結果是一致的。
現在再回到最初的問題,每秒上下文切換多少次才算正常呢?
???? 這個數值其實取決于系統本身的 CPU 性能。在我看來,如果系統的上下文切換次數比較穩定,那么從數百到一萬以內,都應該算是正常的。但當上下文切換次數超過一萬次,或者切換次數出現數量級的增長時,就很可能已經出現了性能問題。
這時,你還需要根據上下文切換的類型,再做具體分析。比方說:
??? 自愿上下文切換變多了,說明進程都在等待資源,有可能發生了 I/O 等其他問題;
??? 非自愿上下文切換變多了,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸;
??? 中斷次數變多了,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。
小結
通過一個 sysbench 的案例,給你講了上下文切換問題的分析思路。碰到上下文切換次數過多的問題時,我們可以借助 vmstat 、 pidstat 和 /proc/interrupts 等工具,來輔助排查性能問題的根源。
首先通過uptime查看系統負載,然后使用mpstat結合pidstat來初步判斷到底是cpu計算量大還是進程爭搶過大或者是io過多,接著使用vmstat分析切換次數,以及切換類型,來進一步判斷到底是io過多導致問題還是進程爭搶激烈導致問題。
總結
以上是生活随笔為你收集整理的2.2 CPU 上下文切换是什么意思?(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2.1 CPU 上下文切换(上)
- 下一篇: 3 当某个应用的CPU使用达到100%,