舞動的操作系統(tǒng):深入了解Linux系統(tǒng)上下文切換
最近排查性能碰到由于上下文切換頻繁導致性能下降的問題,這里做一個對上下文排查的學習記錄。
在計算機科學領(lǐng)域,系統(tǒng)上下文切換是一項至關(guān)重要的操作,尤其在多任務(wù)操作系統(tǒng)中。Linux系統(tǒng)以其高度的穩(wěn)定性和可伸縮性而著名,而系統(tǒng)上下文切換是其核心特性之一。在本文中,我們將深入探討系統(tǒng)上下文切換的概念,以及如何使用vmstat工具來監(jiān)視系統(tǒng)上下文切換的情況。
什么是系統(tǒng)上下文切換
系統(tǒng)上下文切換是指操作系統(tǒng)在不同進程或線程之間切換執(zhí)行的過程。在多任務(wù)操作系統(tǒng)中,這是一項至關(guān)重要的任務(wù),因為它允許多個程序共享處理器時間,以便它們似乎同時運行。系統(tǒng)上下文切換涉及保存當前進程的狀態(tài),切換到另一個進程,并將其狀態(tài)還原,以便它可以繼續(xù)執(zhí)行。這是操作系統(tǒng)內(nèi)核的關(guān)鍵職責之一,以確保公平的資源分配和系統(tǒng)的高效性。
vmstat
在Linux系統(tǒng)中,vmstat是一個非常有用的工具,用于監(jiān)視系統(tǒng)性能,并且可以提供關(guān)于上下文切換的有用信息。您可以使用以下命令來運行vmstat并顯示上下文切換統(tǒng)計信息:
vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b 交換 空閑 緩沖 緩存 si so bi bo in cs us sy id wa st
1 0 0 1956380 62880 877460 0 0 3692 312 572 1251 28 50 21 1 0
0 0 0 1956380 62880 877568 0 0 68 0 160 248 2 0 97 0 0
0 0 0 1956380 62880 877568 0 0 0 0 168 265 2 1 97 0 0
1 0 0 1956380 62880 877564 0 0 0 0 271 523 4 2 94 0 0
1 0 0 1956380 62880 877552 0 0 0 4 225 356 3 1 96 0 0
這將以每秒一次的頻率輸出系統(tǒng)性能信息,其中包括上下文切換的統(tǒng)計數(shù)據(jù)。在輸出中,您將看到如下信息:
- cs(上下文切換):這是系統(tǒng)上下文切換的總數(shù),包括進程切換和中斷切換。
- in(中斷數(shù)):這是自系統(tǒng)啟動以來的中斷總數(shù)。
- r(運行隊列長度):這是正在運行的進程數(shù)。
- b(阻塞隊列長度):這是等待資源的進程數(shù)。
舉個栗子
我們在ubuntu下運行stress-ng -i 100模擬io加壓,在模擬之前使用vmstat 1監(jiān)控上下文切換。
我們可以看到cs從500左右漲到20000多以上,實際應(yīng)用中碰到性能問題需要查上下文時就要使用vmstat來觀察,如果確認了上下文切換比較頻繁,那么如何確認是哪個應(yīng)用導致的呢?這時候就需要pidstat了。這里我在另一個終端已經(jīng)運行起來了。
運行pidstat -w 3 //每隔3秒輸出一次關(guān)于進程上下文切換的統(tǒng)計信息
12時04分17秒 UID PID cswch/s nvcswch/s Command
12時04分20秒 0 14 1.33 0.00 ksoftirqd/0
12時04分20秒 0 15 29.33 0.00 rcu_preempt
12時04分20秒 0 16 0.33 0.00 migration/0
12時04分20秒 0 22 0.33 0.00 migration/1
12時04分20秒 0 23 3.00 0.00 ksoftirqd/1
12時04分20秒 0 35 2.00 0.00 kcompactd0
12時04分20秒 0 48 2.33 0.00 kworker/1:1H-kblockd
12時04分20秒 0 247 707.33 0.00 kworker/u256:29-flush-8:0
12時04分20秒 0 254 0.33 0.00 kworker/0:2H-kblockd
12時04分20秒 0 278 5.00 1.33 jbd2/sda3-8
12時04分20秒 0 380 3.33 0.00 irq/16-vmwgfx
12時04分20秒 127 613 4.00 0.00 systemd-oomd
12時04分20秒 0 642 12.67 0.67 vmtoolsd
12時04分20秒 130 921 0.33 0.00 vnstatd
12時04分20秒 0 1383 1.00 0.00 vmtoolsd
12時04分20秒 998 1576 1.00 0.00 pmproxy
12時04分20秒 0 4294 9.33 9.33 gnome-shell
12時04分20秒 0 4431 2.00 0.00 ibus-daemon
12時04分20秒 0 4506 10.33 0.33 vmtoolsd
12時04分20秒 0 4550 1.00 0.00 ibus-extension-
12時04分20秒 0 4615 1.00 0.00 ibus-engine-lib
12時04分20秒 0 4835 8.33 13.33 gnome-terminal-
12時04分20秒 0 5411 6.67 0.00 kworker/0:2-events
12時04分20秒 0 5796 42.33 0.00 kworker/u256:1-writeback
12時04分20秒 0 7105 8.00 0.00 kworker/1:3-events
12時04分20秒 0 7224 1.00 1.00 vmstat
12時04分20秒 0 7475 6.33 6.33 stress-ng
12時04分20秒 0 7476 6.33 7.00 stress-ng
12時04分20秒 0 7477 5.00 6.00 stress-ng
12時04分20秒 0 7478 5.33 5.00 stress-ng
12時04分20秒 0 7479 5.33 8.00 stress-ng
12時04分20秒 0 7480 5.67 5.67 stress-ng
12時04分20秒 0 7481 5.33 5.67 stress-ng
12時04分20秒 0 7482 4.33 4.67 stress-ng
12時04分20秒 0 7483 5.33 5.33 stress-ng
12時04分20秒 0 7484 5.33 4.67 stress-ng
12時04分20秒 0 7485 4.67 6.00 stress-ng
12時04分20秒 0 7486 4.67 7.00 stress-ng
12時04分20秒 0 7487 4.33 5.00 stress-ng
12時04分20秒 0 7488 4.67 5.33 stress-ng
12時04分20秒 0 7489 5.00 5.00 stress-ng
12時04分20秒 0 7490 4.00 6.33 stress-ng
12時04分20秒 0 7491 5.00 7.00 stress-ng
12時04分20秒 0 7492 5.67 7.00 stress-ng
12時04分20秒 0 7493 5.67 5.00 stress-ng
12時04分20秒 0 7494 5.67 6.33 stress-ng
12時04分20秒 0 7495 5.67 3.67 stress-ng
12時04分20秒 0 7496 5.00 6.00 stress-ng
12時04分20秒 0 7497 5.00 8.33 stress-ng
........后面還有很多stress-ng的進程
從結(jié)果中可以看到有很多stress-ng帶來的上下文切換,這里面還有個占大頭兒的kworker/u256:29-flush-8:0,占了707,他是做什么的呢?
kworker/u256:29-flush-8:0 是Linux內(nèi)核中的一個內(nèi)核線程,它用于執(zhí)行與I/O刷新相關(guān)的任務(wù)。這個線程通常是由kworker進程池中的一個線程執(zhí)行的,負責刷新磁盤緩存中的數(shù)據(jù)到存儲設(shè)備,以確保數(shù)據(jù)的一致性和持久性。
具體來說,kworker/u256:29-flush-8:0 中的部分信息可以解釋如下:
- kworker:這是內(nèi)核工作線程的通用前綴。
- /u256:這是一個標識符,通常是一個數(shù)字,用于唯一標識內(nèi)核工作線程。
- 29:這可能是該特定線程的標識號,用于標識線程在內(nèi)核線程池中的位置。
- flush-8:0:這部分通常描述了該線程正在執(zhí)行的任務(wù),這里是"flush",可能表示磁盤數(shù)據(jù)刷新操作。8:0 可能涉及到與設(shè)備名稱或塊設(shè)備的相關(guān)信息。
這種類型的內(nèi)核線程通常用于后臺任務(wù),以確保數(shù)據(jù)在內(nèi)存和磁盤之間的同步。它在I/O操作中扮演了重要角色,幫助維護數(shù)據(jù)的一致性,并減少數(shù)據(jù)丟失的風險。所以可以確定是stress-ng模擬io加壓帶來的上下文切換。
非自愿與自愿切換
上面pidstat可以看到cswch/s nvcswch/s,這兩個就是自愿上下文切換和非自愿上下文切換。
非自愿上下文切換(Non-Voluntary Context Switches)和自愿上下文切換(Voluntary Context Switches)是多任務(wù)操作系統(tǒng)中的兩種不同類型的上下文切換,它們分別表示進程或線程切換執(zhí)行的原因和方式。
(1) 自愿上下文切換(Voluntary Context Switches):
自愿上下文切換是由進程或線程自身發(fā)起的上下文切換,而不是被操作系統(tǒng)強制執(zhí)行。這通常發(fā)生在以下情況下:
- 進程主動讓出CPU,以便其他就緒狀態(tài)的進程有機會執(zhí)行。這可以是出于合作性多任務(wù)處理的目的,進程知道它已經(jīng)執(zhí)行了足夠的時間,并主動讓出CPU。
- 進程在執(zhí)行期間需要等待某些事件的發(fā)生,如等待I/O操作完成。在這種情況下,進程可能會主動掛起自己,以便其他任務(wù)可以繼續(xù)執(zhí)行。
自愿上下文切換通常是進程協(xié)作和多任務(wù)處理的一部分,它有助于提高系統(tǒng)的效率和公平性。
(2) 非自愿上下文切換(Non-Voluntary Context Switches):
非自愿上下文切換是由操作系統(tǒng)強制執(zhí)行的上下文切換,進程或線程被掛起并切換到就緒狀態(tài)的其他進程或線程。它通常發(fā)生在以下情況下:
- 進程的時間片(CPU分配的時間段)已經(jīng)用盡,操作系統(tǒng)需要將CPU分配給其他進程。
- 進程需要等待某些資源的可用性,如等待磁盤I/O、等待網(wǎng)絡(luò)數(shù)據(jù)等。在這種情況下,進程被掛起,直到資源可用。
非自愿上下文切換是操作系統(tǒng)的一種管理方式,以確保多任務(wù)系統(tǒng)中的進程或線程都有機會獲得CPU時間,防止某個任務(wù)長時間獨占CPU。
總結(jié)起來,自愿上下文切換是由進程自身控制和觸發(fā)的上下文切換,而非自愿上下文切換是由操作系統(tǒng)強制執(zhí)行的,通常是為了分配資源和提高系統(tǒng)的效率。了解這兩種上下文切換類型有助于理解多任務(wù)操作系統(tǒng)如何管理和調(diào)度進程,以確保資源的合理分配和性能的優(yōu)化。
總結(jié)
系統(tǒng)上下文切換是多任務(wù)操作系統(tǒng)的核心功能之一,它確保了資源的公平分配和高效的多任務(wù)處理。通過使用vmstat工具,可以監(jiān)視系統(tǒng)上下文切換的性能統(tǒng)計信息,以便更好地了解系統(tǒng)性能瓶頸問題。