一、優化方向
1,效能指標
從應用負載的視角出發,考慮“吞吐”和“延時”
從系統資源的視角出發,考慮資源使用率、飽和度等
2,效能優化步驟
- 選擇指標評估應用程式和系統的效能;
- 為應用程式和系統設定效能目標;
- 進行效能基準測試;
- 效能分析定位瓶頸;
- 優化系統和應用程式;
- 效能監控和告警。
3,Linux效能工具圖譜
二、平均負載
1,stress
安裝命令:apt install stress
#模擬一個CPU使用率 100%stress -c N
會讓stress生成N個工作程式進行開方運算,以此對CPU產生負載。 stress --cpu 1 --timeout 600
#模擬I/O密集程式stress -i N
會產生N個程式,每個程式反覆呼叫sync()將記憶體上的內容寫到硬碟上, --timeout 600 表示600秒後退出 stress -i 1 --timeout 600
2,sysstat
安裝命令:apt install sysstat
- mpstat 是一個常用的多核cpu效能分析工具,用來實時檢視每個CPU的效能指標,以及所有CPU的平均指標
-
mpstat -P ALL 5 其中-P ALL 表示監控所有CPU 數字5,表示每間隔5秒輸出一組資料
- pidstat 是一個常用的程式效能分析工具,用來實時檢視程式的CPU、記憶體、IO以及上下文切換等效能指標
-
pidstat -u 5 1 每間隔5秒輸出一組資料
3,場景模擬
a>CPU密集
stress
#模擬一個CPU使用率 100% stress -c N 會讓stress生成N個工作程式進行開方運算,以此對CPU產生負載。--timeout 600 表示600秒後退出 stress --cpu 1 --timeout 600
監控uptime,負載在升高
mpstat,發現一個CPU的使用率高達100%,但是iowait為0,說明平均負載的升高由於CPU的使用率為100%
pidstat,發現是stress程式導致CPU使用率升高
b>I/O密集
stress
#模擬I/O密集程式 stress -i N 會產生N個程式,每個程式反覆呼叫sync()將記憶體上的內容寫到硬碟上 stress -i 1 --timeout 600
監控uptime,負載在升高
mpstat,發現一個系統CPU使用率升至23.87%,iowait高達67.53% 。說明平均負載的升高由於iowait的升高
pidstat,發現是由於stress程式導致
c>大量程式的場景
stress
stress -c 8 --timeout 600
uptime
pidstat,發現8個程式在爭搶2個CPU,每個程式等待CPU的時間高達75%,導致CPU過載
三、CPU的上下文切換
1,基本概念
CPU暫存器:CPU內建的容量小、但速度極快的記憶體
程式計數器:用於儲存CPU正在執行的指令位置、或者即將執行的下一條指令位置
CPU上下文:CPU暫存器和程式計數器所必須的依賴環境
CPU上下文切換:先把前一個任務的CPU上下文(也就是CPU暫存器和程式計數器)儲存起來,然後載入新任務的上下文到這些暫存器和程式計數器,最後再跳轉到程式計數器所指的新位置,執行新任務。
2,分類
a>程式上下文切換
Linux按照特權等級,把程式的執行空間分為核心空間和使用者空間,分別對應CPU特權等級的 Ring 0 和Ring 3
- 核心空間(Ring 0)具有最高許可權,可以直接訪問所有資源
- 使用者空間(Ring 3)只能訪問受限資源,不能直接訪問記憶體等硬體裝置,必須通過系統呼叫陷入核心中,才能訪問這些特權資源
換個角度,也就是程式既可以在使用者空間執行,又可以在核心空間執行。程式在使用者空間執行時,被稱為程式的使用者態,而陷入核心空間的時候,被稱為程式的核心態。
在程式切換時才需要切換上下文,也就是程式排程時。Linux為每個CPU都維護了一個就緒佇列,將活躍程式按照優先順序和等待CPU的時間排序,然後選擇最需要CPU的程式,也就是優先順序最高和等待CPU時間最長的程式執行。涉及到的場景包括:
- 為了保證所有程式可以得到公平排程,CPU時間被劃分為一段段的時間片,這些時間片再被輪流分配給各個程式。這樣,當某個程式的時間片耗盡了,就會被系統掛起,切換到其他正在等待CPU的程式執行
- 程式在系統資源不足(比如記憶體不足)時,要等到資源滿足後才可以執行,這個時候程式也會被掛起,並有系統排程其他程式執行
- 當程式通過睡眠函式sleep這樣的方法將自己主動掛起時,自然也會重新排程
- 當有優先順序更高的程式執行時,為了保證高優先順序程式的執行,當前程式會被掛起,由高優先順序程式來執行
- 當發生硬體中斷時,CPU上的程式會被中斷掛起,轉而執行核心中的中斷服務程式
b>執行緒上下文切換
執行緒是排程的基本單位,而程式則是資源擁有的基本單位。
- 當程式只有一個執行緒時,可以認為程式就等於執行緒
- 當程式擁有多個執行緒時,這些執行緒會共享相同的虛擬記憶體和全域性變數等資源。這些資源在上下文切換時不需要修改
- 執行緒也有自己的私有資料,比如棧和暫存器,這些在上下文切換時也需要儲存
執行緒上下文切換:1,前後兩個執行緒屬於不同程式,由於資源不同就是程式上下文切換;2,前後兩個執行緒屬於同一個程式,此時虛擬記憶體共享,切換時只需要切換執行緒的私有資料、暫存器等不共享的資料。
c>中斷上下文切換
- 為了快速響應硬體的事件,中斷處理會打斷程式的正常排程和執行,轉而呼叫中斷處理程式,響應裝置事件。而在打斷其他程式時,就需要將程式當前的狀態儲存起來,這樣在中斷結束後,程式仍然可以從原來的狀態恢復執行
- 與程式上下文切換不同,中斷上下文切換並不涉及程式的使用者態。所以,即便中斷過程打斷了一個正處在使用者態的程式,也不需要儲存和恢復這個程式的虛擬記憶體、全域性變數等使用者態資源。中斷上下文,其實只包括核心態中斷服務程式執行所必需的狀態,包括CPU暫存器、核心堆疊、硬體中斷引數等
3,CPU上下文切換實戰
a>vmstat
- cs(context switch)是每秒上下文切換的次數
- in(interrupt)是每秒中斷的次數
- r(Running or Runnable)是就緒佇列的長度,也就是正在執行和等待的CPU的程式數‘
- b(Blocked)是處於不可中斷睡眠狀態的程式數
b>pidstat
vmstat只給出了系統總體的上下文切換情況,要想檢視每個程式的詳細情況,就需要使用我們pidstat。加上-w選項,則可以檢視每個程式上下文切換的情況
- cswch(voluntary context switches),每秒自願上下文切換次數。指程式無法獲取所需要資源,導致的上下文切換。比如:I/O、記憶體等系統資源不足時,就會發生自願上下文切換。
- nvcswch(non voluntary context switches),每秒非自願上下文切換。指程式由於時間片已到等原因,被系統強制排程,程式發生的上下文切換。比如:大量程式都在爭搶CPU時,就容易發生非自願上下文切換。
c>案例實操
檢視系統的上下文切換次數
採用sysbench進行壓測
再次檢視vmstat
發現cs列的上下文切換數量從之前的35驟然上升到了139萬多。同時,r列:就緒佇列的長度為8,遠超CPU的個數2,所以判定有大量的CPU競爭;us(user)和sy(system)列:這兩列的CPU使用率加起來上升到了100%,其中系統CPU使用率,也就是sy列高達84%,說明CPU主要是被核心佔用了;in列:中斷次數也上升到1萬左右,說明中斷處理也是個潛在的問題。綜合這幾個指標,系統的就緒佇列過長,也就是正在執行和等待CPU的程式數過多,導致大量的上下文切換,而上下文切換又導致系統的CPU的佔用率升高。
採用pidstat分析
- CPU使用率升高果然是sysbench導致的,已達100%
- 非自願上下文切換最高的為pidstat,自願上下文切換頻率最高的執行緒為kworker和sshd
- 問題:pidstat輸出的上線文切換明顯小於vmstat輸出的上下文切換。採用man pidstat 發現,pidstat預設顯示程式的指標資料,加上-t引數後,才會輸出執行緒指標
結合兩次的pidstat可以看出,sysbench(主執行緒)的上下文切換次數看起來並不太多,但它的子執行緒的上下文切換次數卻很多。
採用watch觀察interrupts中斷
觀察發現,變化速度最快的是重排程中斷(RES),表示喚醒空閒狀態的CPU來排程新的任務執行。這是多處理器系統(SMP)中,排程器用來分散任務到不同CPU的機制,通常也被稱為處理器間中斷(Inter-Processor Interrupts, IPI)。
d>總結
如果系統的上下文切換次數比較穩定,那麼從數百到一萬內,都應該算是正常的。當上下文切換次數超過一萬次,或者切換次數出現數量級的增長時,都很可能已經出現了效能問題:
- 自願上下文切換變多,說明程式都在等待資源,有可能發生了I/O等其他問題
- 非自願上下文切換變多,說明程式都在被強制排程,也就是都在爭搶CPU,說明CPU的確成了瓶頸
- 中斷次數變多了,說明CPU被中斷處理程式佔用,需要檢視/proc/interrupts檔案來分析具體的中斷型別