04 | 基礎篇:經常說的 CPU 上下文切換是什麼意思?(下)

上一節,我給你講了 CPU 上下文切換的工作原理。簡單回顧一下,CPU 上下文切換是保證 Linux 系統正常工作的一個核心功能,按照不同場景,可以分爲進程上下文切換、線程上下文切換和中斷上下文切換。具體的概念和區別,你也要在腦海中過一遍,忘了的話及時查看上一篇。

今天我們就接着來看,究竟怎麼分析 CPU 上下文切換的問題。

怎麼查看系統的上下文切換情況

通過前面學習我們知道,過多的上下文切換,會把 CPU 時間消耗在寄存器、內核棧以及虛擬內存等數據的保存和恢復上,縮短進程真正運行的時間,成了系統性能大幅下降的一個元兇。

既然上下文切換對系統性能影響那麼大,你肯定迫不及待想知道,到底要怎麼查看上下文切換呢?在這裏,我們可以使用 vmstat 這個工具,來查詢系統的上下文切換情況。

vmstat 是一個常用的系統性能分析工具,主要用來分析系統的內存使用情況,也常用來分析 CPU 上下文切換和中斷的次數。

比如,下面就是一個 vmstat 的使用示例:

# 每隔5秒輸出1組數據
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 7005360  91564 818900    0    0     0     0   25   33  0  0 100  0  0

我們一起來看這個結果,你可以先試着自己解讀每列的含義。在這裏,我重點強調下,需要特別關注的四列內容:

  • cs(context switch)是每秒上下文切換的次數。
  • in(interrupt)則是每秒中斷的次數。
  • r(Running or Runnable)是就緒隊列的長度,也就是正在運行和等待 CPU 的進程數。
  • b(Blocked)則是處於不可中斷睡眠狀態的進程數。

可以看到,這個例子中的上下文切換次數 cs 是 33 次,而系統中斷次數 in 則是 25 次,而就緒隊列長度 r 和不可中斷狀態進程數 b 都是 0。

vmstat 只給出了系統總體的上下文切換情況,要想查看每個進程的詳細情況,就需要使用我們前面提到過的 pidstat 了。給它加上 -w 選項,你就可以查看每個進程上下文切換的情況了。

比如說:

# 每隔5秒輸出1組數據
$ pidstat -w 5
Linux 4.15.0 (ubuntu)  09/23/18  _x86_64_  (2 CPU)

08:18:26      UID       PID   cswch/s nvcswch/s  Command
08:18:31        0         1      0.20      0.00  systemd
08:18:31        0         8      5.40      0.00  rcu_sched
...

這個結果中有兩列內容是我們的重點關注對象。一個是 cswch ,表示每秒自願上下文切換(voluntary context switches)的次數,另一個則是 nvcswch ,表示每秒非自願上下文切換(non voluntary context switches)的次數。

這兩個概念你一定要牢牢記住,因爲它們意味着不同的性能問題:

  • 所謂自願上下文切換,是指進程無法獲取所需資源,導致的上下文切換。比如說, I/O、內存等系統資源不足時,就會發生自願上下文切換。
  • 非自願上下文切換,則是指進程由於時間片已到等原因,被系統強制調度,進而發生的上下文切換。比如說,大量進程都在爭搶 CPU 時,就容易發生非自願上下文切換。

案例分析

知道了怎麼查看這些指標,另一個問題又來了,上下文切換頻率是多少次纔算正常呢?別急着要答案,同樣的,我們先來看一個上下文切換的案例。通過案例實戰演練,你自己就可以分析並找出這個標準了。

你的準備

今天的案例,我們將使用 sysbench 來模擬系統多線程調度切換的情況。

sysbench 是一個多線程的基準測試工具,一般用來評估不同系統參數下的數據庫負載情況。當然,在這次案例中,我們只把它當成一個異常進程來看,作用是模擬上下文切換過多的問題。

下面的案例基於Centos7,當然,其他的 Linux 系統同樣適用。我使用的案例環境如下所示:機器配置:

  • 2 CPU,8GB 內存
  • 預先安裝 sysbench 和 sysstat 包,如 yum install sysbench sysstat

正式操作開始前,你需要打開三個終端,登錄到同一臺 Linux 機器中,並安裝好上面提到的兩個軟件包。包的安裝,可以先 Google 一下自行解決,如果仍然有問題的,在留言區寫下你的情況。

另外注意,下面所有命令,都默認以 root 用戶運行。所以,如果你是用普通用戶登陸的系統,記住先運行 sudo su root 命令切換到 root 用戶。

安裝完成後,你可以先用 vmstat 看一下空閒系統的上下文切換次數:

# 間隔1秒後輸出1組數據
$ vmstat 1 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 6984064  92668 830896    0    0     2    19   19   35  1  0 99  0  0

操作和分析

接下來,我們正式進入實戰操作。首先,在第一個終端裏運行 sysbench ,模擬系統多線程調度的瓶頸:

# 以10個線程運行5分鐘的基準測試,模擬多線程切換的問題
$ sysbench --threads=10 --max-time=300 threads run

接着,在第二個終端運行 vmstat ,觀察上下文切換情況:

# 每隔1秒輸出1組數據(需要Ctrl+C才結束)
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 6  0      0 6487428 118240 1292772    0    0     0     0 9019 1398830 16 84  0  0  0
 8  0      0 6487428 118240 1292772    0    0     0     0 10191 1392312 16 84  0  0  0

你應該可以發現,cs 列的上下文切換次數從之前的 35 驟然上升到了 139 萬。同時,注意觀察其他幾個指標:

  • r 列:就緒隊列的長度已經到了 8,遠遠超過了系統 CPU 的個數 2,所以肯定會有大量的 CPU 競爭。
  • us(user)和 sy(system)列:這兩列的 CPU 使用率加起來上升到了 100%,其中系統 CPU 使用率,也就是 sy 列高達 84%,說明 CPU 主要是被內核佔用了。
  • in 列:中斷次數也上升到了 1 萬左右,說明中斷處理也是個潛在的問題。

綜合這幾個指標,我們可以知道,系統的就緒隊列過長,也就是正在運行和等待 CPU 的進程數過多,導致了大量的上下文切換,而上下文切換又導致了系統 CPU 的佔用率升高。

那麼到底是什麼進程導致了這些問題呢?

我們繼續分析,在第三個終端再用 pidstat 來看一下, CPU 和進程上下文切換的情況:

# 每隔1秒輸出1組數據(需要 Ctrl+C 才結束)
# -w參數表示輸出進程切換指標,而-u參數則表示輸出CPU使用指標
$ pidstat -w -u 1
08:06:33      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
08:06:34        0     10488   30.00  100.00    0.00    0.00  100.00     0  sysbench
08:06:34        0     26326    0.00    1.00    0.00    0.00    1.00     0  kworker/u4:2

08:06:33      UID       PID   cswch/s nvcswch/s  Command
08:06:34        0         8     11.00      0.00  rcu_sched
08:06:34        0        16      1.00      0.00  ksoftirqd/1
08:06:34        0       471      1.00      0.00  hv_balloon
08:06:34        0      1230      1.00      0.00  iscsid
08:06:34        0      4089      1.00      0.00  kworker/1:5
08:06:34        0      4333      1.00      0.00  kworker/0:3
08:06:34        0     10499      1.00    224.00  pidstat
08:06:34        0     26326    236.00      0.00  kworker/u4:2
08:06:34     1000     26784    223.00      0.00  sshd

從 pidstat 的輸出你可以發現,CPU 使用率的升高果然是 sysbench 導致的,它的 CPU 使用率已經達到了 100%。但上下文切換則是來自其他進程,包括非自願上下文切換頻率最高的 pidstat ,以及自願上下文切換頻率最高的內核線程 kworker 和 sshd。

不過,細心的你肯定也發現了一個怪異的事兒:pidstat 輸出的上下文切換次數,加起來也就幾百,比 vmstat 的 139 萬明顯小了太多。這是怎麼回事呢?難道是工具本身出了錯嗎?

彆着急,在懷疑工具之前,我們再來回想一下,前面講到的幾種上下文切換場景。其中有一點提到, Linux 調度的基本單位實際上是線程,而我們的場景 sysbench 模擬的也是線程的調度問題,那麼,是不是 pidstat 忽略了線程的數據呢?

通過運行 man pidstat ,你會發現,pidstat 默認顯示進程的指標數據,加上 -t 參數後,纔會輸出線程的指標。

所以,我們可以在第三個終端裏, Ctrl+C 停止剛纔的 pidstat 命令,再加上 -t 參數,重試一下看看:

# 每隔1秒輸出一組數據(需要 Ctrl+C 才結束)
# -wt 參數表示輸出線程的上下文切換指標
$ pidstat -wt 1
08:14:05      UID      TGID       TID   cswch/s nvcswch/s  Command
...
08:14:05        0     10551         -      6.00      0.00  sysbench
08:14:05        0         -     10551      6.00      0.00  |__sysbench
08:14:05        0         -     10552  18911.00 103740.00  |__sysbench
08:14:05        0         -     10553  18915.00 100955.00  |__sysbench
08:14:05        0         -     10554  18827.00 103954.00  |__sysbench
...

現在你就能看到了,雖然 sysbench 進程(也就是主線程)的上下文切換次數看起來並不多,但它的子線程的上下文切換次數卻有很多。看來,上下文切換罪魁禍首,還是過多的 sysbench 線程。

我們已經找到了上下文切換次數增多的根源,那是不是到這兒就可以結束了呢?

當然不是。不知道你還記不記得,前面在觀察系統指標時,除了上下文切換頻率驟然升高,還有一個指標也有很大的變化。是的,正是中斷次數。中斷次數也上升到了 1 萬,但到底是什麼類型的中斷上升了,現在還不清楚。我們接下來繼續抽絲剝繭找源頭。

既然是中斷,我們都知道,它只發生在內核態,而 pidstat 只是一個進程的性能分析工具,並不提供任何關於中斷的詳細信息,怎樣才能知道中斷髮生的類型呢?

沒錯,那就是從 /proc/interrupts 這個只讀文件中讀取。/proc 實際上是 Linux 的一個虛擬文件系統,用於內核空間與用戶空間之間的通信。/proc/interrupts 就是這種通信機制的一部分,提供了一個只讀的中斷使用情況。

我們還是在第三個終端裏, Ctrl+C 停止剛纔的 pidstat 命令,然後運行下面的命令,觀察中斷的變化情況:

# -d 參數表示高亮顯示變化的區域
$ watch -d cat /proc/interrupts
           CPU0       CPU1
...
RES:    2450431    5279697   Rescheduling interrupts
...

觀察一段時間,你可以發現,變化速度最快的是重調度中斷(RES),這個中斷類型表示,喚醒空閒狀態的 CPU 來調度新的任務運行。這是多處理器系統(SMP)中,調度器用來分散任務到不同 CPU 的機制,通常也被稱爲處理器間中斷(Inter-Processor Interrupts,IPI)。

所以,這裏的中斷升高還是因爲過多任務的調度問題,跟前面上下文切換次數的分析結果是一致的。

通過這個案例,你應該也發現了多工具、多方面指標對比觀測的好處。如果最開始時,我們只用了 pidstat 觀測,這些很嚴重的上下文切換線程,壓根兒就發現不了了。

現在再回到最初的問題,每秒上下文切換多少次纔算正常呢?

這個數值其實取決於系統本身的 CPU 性能。在我看來,如果系統的上下文切換次數比較穩定,那麼從數百到一萬以內,都應該算是正常的。但當上下文切換次數超過一萬次,或者切換次數出現數量級的增長時,就很可能已經出現了性能問題。

這時,你還需要根據上下文切換的類型,再做具體分析。比方說:

  • 自願上下文切換變多了,說明進程都在等待資源,有可能發生了 I/O 等其他問題;
  • 非自願上下文切換變多了,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 的確成了瓶頸;
  • 中斷次數變多了,說明 CPU 被中斷處理程序佔用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。

小結

今天,我通過一個 sysbench 的案例,給你講了上下文切換問題的分析思路。碰到上下文切換次數過多的問題時,我們可以藉助 vmstat 、 pidstat 和 /proc/interrupts 等工具,來輔助排查性能問題的根源。

課後作業

整理vmstat 、 pidstat相關命令使用方法

注意事項

1.執行watch -d cat /proc/interrupts不顯示res的,縮小窗口

2.如果無法模擬出RES變化,請確定你的是否是單核CPU,案例需要雙核CPU以上

軟件測試汪簡書地址
軟件測試汪博客地址

歡迎關注微信公衆號:軟件測試汪。軟件測試交流羣:809111560

轉載請注意出處,謝謝合作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章