
本文轉載自微信公眾號「運維開發故事」,作者沒有文案的夏老師 。轉載本文請聯系運維開發故事公眾號。
1.進程概念
進程定義
進程是并發環境下,一個具有獨立功能的程序在某個數據集上的一次執行活動,它是操作系統進行資源分配和保護的基本單位,也是執行的單位。
PCB
進程控制塊(Process Control Block,PCB)是為了描述和控制進程的運行而定義的一種數表結構,它是進程存在的唯一標志,也是進程實體的一部分。操作系統對進程的管理和控制主要以PCB為依據。PCB中包括了操作系統所需要的進程運行的所有信息。
進程的上下文
用戶級上下文: 正文、數據、用戶堆棧以及共享存儲區;寄存器上下文: 通用寄存器、程序寄存器(IP)、處理器狀態寄存器(EFLAGS)、棧指針(ESP);系統級上下文: 進程控制塊task_struct、內存管理信息(mm_struct、vm_area_struct、pgd、pte)、內核棧。
2.線程概念
線程上下文
多線程環境下的進程定義,很顯然,進程是系統進行資源分配和保護的基本單位。進程包括容納進程映像的一個虛擬地址空間,以及對CPU、I/O資源、文件以及其他資源的有保護有控制的訪問。
可見,一個進程可以劃分為兩個部分:一部分是資源部分,一部分是線程部分。
TCB
線程由線程控制塊(Thread Control Block,TCB)、用戶堆棧、系統堆棧以及一組處理器狀態寄存器和一個私用內存存儲區組成。
3.上下文
cpu上下文
CPU 寄存器,是 CPU 內置的容量小、但速度極快的內存。而程序計數器,則是用來存儲 CPU 正在執行的指令位置、或者即將執行的下一條指令位置。它們都是 CPU 在運行任何任務前,必須的依賴環境,因此也被叫做 CPU 上下文。
進程上下文切換
每當內核壓入一個新的系統上下文層時,它就要保存一個進程的上下文。特別是當系統收到一個中斷,或一個進程執行系統調用,或當內核做上下文切換時,就要對進程的上下文進行保存。上下文切換情況:
一個進程結束,需要從隊列中重新選擇一個進程運行。
如果進程在系統資源不足(內存不足等),則返回到運行隊列,并由系統調度其他進程運行。
如果不訪問磁盤I/O等資源就不能繼續,它會自己主動掛起時,自然也會重新調度。
當有優先級更高的進程運行時,為了保證高優先級進程的運行,當前進程會被掛起,由高優先級進程來運行。
發生硬中斷,CPU 上的進程會被中斷掛起,轉而執行內核中的中斷服務程序。
了解這幾個場景是非常有必要的,因為一旦出現上下文切換的性能問題,它們就是幕后兇手。
線程上下文切換
第一種, 前后兩個線程屬于不同進程。此時,因為資源不共享,所以切換過程就跟進程上下文切換是一樣。
第二種,前后兩個線程屬于同一個進程。此時,因為虛擬內存是共享的,所以在切換時,虛擬內存這些資源就保持不動,只需要切換線程的私有數據、寄存器等不共享的數據。到這里你應該也發現了,雖然同為上下文切換,但同進程內的線程切換,要比多進程間的切換消耗更少的資源,而這,也正是多線程代替多進程的一個優勢。
雖然同為上下文切換,但同進程內的線程切換,要比多進程間的切換消耗更少的資源,而這,也正是多線程代替多進程的一個優勢。
系統調用
系統調用(system call),指運行在用戶空間的程序向操作系統內核請求需要更高權限運行的服務。系統調用提供用戶程序與操作系統之間的接口。大多數系統交互式操作需求在內核態運行。
典型實現(Linux)
Linux 在x86上的系統調用通過 int 80h 實現,用系統調用號來區分入口函數。操作系統實現系統調用的基本過程是:
應用程序調用庫函數(API);
API 將系統調用號存入 EAX,然后通過中斷調用使系統進入內核態;
內核中的中斷處理函數根據系統調用號,調用對應的內核函數(系統調用);
系統調用完成相應功能,將返回值存入 EAX,返回到中斷處理函數;
中斷處理函數返回到 API 中;
API 將 EAX 返回給應用程序。
CPU 寄存器里原來用戶態的指令位置,需要先保存起來。接著,為了執行內核態代碼,CPU 寄存器需要更新為內核態指令的新位置。最后才是跳轉到內核態運行內核任務。而系統調用結束后,CPU 寄存器需要恢復原來保存的用戶態,然后再切換到用戶空間,繼續運行進程。
總結:一次系統調用的過程,其實是發生了兩次 CPU 上下文切換。但是主要是CPU寄存器,不會涉及到虛擬內存等資源。
中斷上下文切換
無論是硬件中斷(如來自時鐘和外設)、可編程中斷(programmed interrupt)(執行引起"軟件中斷"(software interrupt)的指令),還是例外中斷(如頁面錯),都由系統負責處理。
硬件通過觸發信號,向CPU發送中斷信號,導致內核調用中斷處理程序,進入內核空間。這個過程中,硬件的一些變量和參數也要傳遞給內核, 內核通過這些參數進行中斷處理。
當發生一個中斷時,如果CPU正在比該中斷級低的處理機運行級上運行,它就在解碼下條指令之前,接收該中斷,并提高處理機執行級。這樣,在它處理當前的中斷時,就不會響應該級別或更低級別的中斷,從而維護了內核數據結構的完整性。內核處理中斷的操作順序如下。
切換到到內核線程并對正在執行的進程,保存其當前寄存器上下文并創建(壓入)一個新上下文。
確定中斷源,識別中斷類型(如時鐘或磁盤)。若可以的話,還識別中斷的單元號(如哪個磁盤機引起中斷)。當系統接收一個中斷時,它從機器中得到一個數,系統把這個數用作查表的偏移量。這個表通常被稱為中斷向量(interrupt vector)。中斷向量的內容因機器而異。但一般都含有每種中斷源的中斷處理程序的地址以及中斷處理程序取得參數的方式。內核調用中斷處理程序。從邏輯上講,新上下文層的核心棧不同于前一上下文層的核心棧。在實現方法上,有些是用正在運行的進程的核心棧存放中斷處理程序的棧結構,另一些則是使用全局中斷棧存放中斷處理程序的棧結構,后者能保證中斷處理程序不用進行上下文切換就能返回。
中斷處理程序工作完畢前返回。內核執行一系列特殊機器指令。這些指令恢復前一上下文層的寄存器上下文和核心棧,使它們和中斷發生時的情況一樣,并恢復該上下文層的運行。相應的進程的工作情況可能會受到中斷處理程序的影響,因為中斷處理程序可能已修改過內核的全局數據結構,并喚醒過睡眠的進程。但在一般情況下,進程會像從來未發生過中斷一樣繼續運行。
4.分析linux系統的cpu上下文切換
工具
vmstat
vmstat 是一個常用的系統性能分析工具,主要用來分析系統的內存使用情況,也常用來分析 CPU 上下文切換和中斷的次數。
$vmstat5rocs-----------memory-------------swap-------io-----system--------cpu-----rbswpdfreebuffcachesisobiboincsussyidwast200274588681459964781912000100009900000274593881459964781928000389371579111990000027457272145996478194800010902215774119900
你可以通過man手冊解讀每列的含義?,F在我們重點強調:
cs(context switch)是每秒上下文切換的次數。
in(interrupt)是每秒中斷的次數。
r(Running or Runnable)是就緒隊列的長度,也就是正在運行和等待 CPU 的進程數。
b(Blocked)是處于不可中斷睡眠狀態的進程數。
vmstat 只給出了系統總體的上下文切換情況,要想查看每個進程的詳細情況,就需要使用我們前面提到過的 pidstat 了。給它加上 -w 選項,你就可以查看每個進程上下文切換的情況了。
#每隔5秒輸出1組數據$pidstat-wu-t5Linux4.4.0-142-generic(i-0nxoa13q)07/22/2021_x86_64_(16CPU)03:54:53PMUIDTGIDTID%usr%system%guest%CPUCPUCommand03:54:58PM03-0.000.200.000.200ksoftirqd/003:54:58PM0-30.000.200.000.200|__ksoftirqd/003:54:58PM07-0.000.200.000.2012rcu_sched03:54:58PM06849-0.800.000.000.8010dockerd...03:54:53PMUIDTGIDTIDcswch/snvcswch/sCommand03:54:58PM03-64.210.00ksoftirqd/003:54:58PM0-364.210.00|__ksoftirqd/003:54:58PM07-98.010.00rcu_sched03:54:58PM0-798.010.00|__rcu_sched...
這個結果中有兩列內容是我們的重點關注對象。一個是 cswch ,表示每秒自愿上下文切換(voluntary context switches)的次數,另一個則是 nvcswch ,表示每秒非自愿上下文切換(non voluntary context switches)的次數。這兩個概念你一定要牢牢記住,因為它們意味著不同的性能問題:
自愿上下文切換,是指進程無法獲取所需資源,導致的上下文切換。比如說, I/O、內存等系統資源不足時,就會發生自愿上下文切換。
非自愿上下文切換,則是指進程由于時間片已到等原因,被系統強制調度,進而發生的上下文切換。比如說,大量進程都在爭搶 CPU 時,就容易發生非自愿上下文切換。
proc文件系統
Linux內核提供了一種通過?/proc?文件系統,在運行時訪問內核內部數據結構、改變內核設置的機制。proc文件系統是一個偽文件系統,它只存在內存當中,而不占用外存空間。它以文件系統的方式為訪問系統內核數據的操作提供接口。深入了解可以去看這篇文章:https://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html中斷次數變多了,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。
sysbench壓力測試
sysbench是一個開源的、模塊化的、跨平臺的多線程性能測試工具,可以用來進行CPU、內存、磁盤I/O、線程、數據庫的性能測試。Sysbench的測試主要包括以下幾個方面:
1、磁盤io性能
2、cpu性能
3、內存分配及傳輸速度
4、POSIX線程性能
5、調度程序性能
6、數據庫性能(OLTP基準測試)
下面的案例基于 Ubuntu 18.04,當然,其他的 Linux 系統同樣適用。我使用的案例環境如下所示:
機器配置:4 CPU,8GB
預先安裝 sysbench 和 sysstat 包,如 apt install sysbench sysstat。
#以10個線程運行5分鐘的基準測試,模擬多線程切換的問題sysbench--threads=10--max-time=300threadsrun
top命令:
top-11:10:05up10days,35min,3users,loadaverage:2.72,1.27,0.64Tasks:120total,1running,119sleeping,0stopped,0zombie%Cpu0:22.3us,69.4sy,0.0ni,8.3id,0.0wa,0.0hi,0.0si,0.0st%Cpu1:23.2us,66.3sy,0.0ni,10.4id,0.0wa,0.0hi,0.0si,0.0st%Cpu2:22.3us,67.1sy,0.0ni,10.6id,0.0wa,0.0hi,0.0si,0.0st%Cpu3:22.8us,68.8sy,0.0ni,8.4id,0.0wa,0.0hi,0.0si,0.0stKiBMem:8008272total,2646040free,3650548used,1711684buff/cacheKiBSwap:0total,0free,0used.4048240availMemPIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND18770root2009436836722696S378.40.02:43.48sysbench
看到內核cpu使用率很高??梢蛇M程為sysbench。此時可以使用pidstat命令查看:
pidstat-wu-t5-p18770Linux3.10.0-1160.15.2.el7.x86_64(pulsar-1-348d-0002-f741-0002)2021年07月23日_x86_64_(4CPU)11時11分26秒UIDTGIDTID%usr%system%guest%CPUCPUCommand11時11分31秒018770-98.60100.000.00100.003sysbench11時11分31秒0-187700.000.000.000.003|__sysbench11時11分31秒0-187719.0028.600.0037.602|__sysbench11時11分31秒0-187729.6027.400.0037.003|__sysbench11時11分31秒0-187739.8029.000.0038.803|__sysbench11時11分31秒0-187749.6027.800.0037.402|__sysbench11時11分31秒0-187759.8029.000.0038.801|__sysbench11時11分31秒0-1877610.4027.800.0038.202|__sysbench11時11分31秒0-1877711.2027.000.0038.201|__sysbench11時11分31秒0-187789.8027.400.0037.202|__sysbench11時11分31秒0-187799.8028.200.0038.002|__sysbench11時11分31秒0-187809.8028.400.0038.200|__sysbench11時11分26秒UIDTGIDTIDcswch/snvcswch/sCommand11時11分31秒018770-0.000.00sysbench11時11分31秒0-187700.000.00|__sysbench11時11分31秒0-1877147647.40132455.60|__sysbench11時11分31秒0-1877247523.60148473.80|__sysbench11時11分31秒0-1877344959.80162137.20|__sysbench11時11分31秒0-1877446765.00138126.60|__sysbench11時11分31秒0-1877547758.40157361.60|__sysbench11時11分31秒0-1877647324.00142616.40|__sysbench11時11分31秒0-1877748346.40145743.60|__sysbench11時11分31秒0-1877849163.60140320.40|__sysbench11時11分31秒0-1877947157.00144586.60|__sysbench11時11分31秒0-1878046882.20144493.00|__sysbench
非自愿上下文切換為15萬左右,說明系統存在強制調度,都在爭搶cpu時間,說明 CPU 為系統瓶頸。
上下文切換多少次才算正常?
這個數值其實取決于系統本身的 CPU 性能。如果系統的上下文切換次數比較穩定,且內核cpu使用率很低,都應該算是正常的。當上下文切換在一萬左右波動,且內核cpu使用率偏高,就很可能出現了性能問題。
總結
上下文切換發生在操作系統內核中。當看到內核cpu使用率過大,考慮在發生上下文切換。
自愿上下文切換變多了,說明進程都在等待資源,有可能發生了 I/O 等其他問題;
非自愿上下文切換變多了,說明進程都在被強制調度,也就是都在爭搶 CPU,說明 CPU 為系統瓶頸;
中斷次數變多了,說明 CPU 被中斷處理程序占用,還需要通過查看 /proc/interrupts 文件來分析具體的中斷類型。
聲明:本文僅為傳遞更多網絡信息,不代表IT資訊網觀點和意見,僅供參考了解,更不能作為投資使用依據。