1.0 效能監控介紹
效能調優是一個尋找系統瓶頸並調節作業系統以消除這些瓶頸的過程。許多系統管理員認為效能調優就像按菜譜做菜一樣:簡單設定幾個系統參數就可以解決一個問題。其實不是這樣的,效能調優是在調節作業系統的各個子系統,以期在他們之間取得一種平衡,達到所需的最佳效能。這些子系統包括:CPU、記憶體、IO、網路。
這些子系統之間高度依賴,其中任意一個子系統出現使用瓶頸都很可能導致其他子系統出現問題。比如:
- 大量的記憶體讀入請求會塞滿記憶體隊列
- 大量的網路吞吐能夠耗盡CPU資源
- 為了保持記憶體隊列空閑可能會耗盡CPU資源
- 大量記憶體到磁碟寫請求可能耗盡CPU和IO資源
為了調優一個系統,首先必須定位到瓶頸在哪裡。有時候看起來是某個子系統出現了問題,但實際可能是另外一個子系統過載引起的。
1.1 判斷應用的類型
為了理解從哪裡開始調優效能,最重要的是先分析和理解一個系統的表現。應用一般被分為兩類:
- IO型:IO型應用會消耗大量的記憶體及其下的儲存系統,這是因為IO型的應用會(在記憶體中)處理大量的資料。IO型的應用一般來說不會消耗太多的CPU和網路資源(除非儲存系統是構建在網路之上的)。IO型的應用一般只使用CPU來產生一個IO請求然後就進入睡眠狀態了。資料庫通常被認為是一個的IO型應用。
- CPU型:顧名思義,CPU型應用會消耗大量CPU資源。CPU應用需要消耗CPU資源來完成一些批處理工作或者數學運算。大容量的web伺服器、郵件伺服器以及各種類型的渲染伺服器通常被認為是CPU型的應用。
1.2 設定基準資料
因為對系統的預期和定製可能不同,系統效能表現的好壞不能一概而論。因此,先用弄清一個系統的效能預期才能判斷該系統是否有效能問題。所以我們需要先設定一個基準資料,即先統計一個可接受效能狀態下各項指標的資料。以後可以用該資料來做效能對比。
下面是一個系統基準和高利用率的效能資料對比樣本:
看錶示CPU空閑率的最後一列(id)我們可以知道基準的CPU空閑率在79%-100%之間。而在第二個圖片中我們看到CPU資源沒有空閑,被100%佔用了。下面需要做的就是判斷如此高的CPU佔用率是不是預期中的了。
2.0 安裝監控工具
大部分Unix系統發布的時候會內建一系列的監控工具,這些監控工具自Unix誕生起就已經成為系統的一部分了。Linux把這些監控工具作為系統的一部分或者附件發行。基本上,所有的Linux發行版本都有包含這些工具的安裝包。儘管類似的開源和第三方的監控工具也不少,這篇文章主要還是介紹這些內建工具的使用。
這篇文章將介紹如何應用下列工具來監控系統效能:
Tool |
Description |
Base |
Repository |
vmstat |
all purpose performance tool |
yes |
yes |
mpstat |
provide statistics per CPU |
no |
yes |
sar |
all purpose performance monitoring tool |
no |
yes |
iostat |
provides disk statistics |
no |
yes |
netstat |
procides network statistics |
yes |
yes |
dstat |
monitoring statistics aggregator |
no |
in most distributions |
iptraf |
traffic monitoring dashboard |
no |
yes |
netperf |
network bandwidth tool |
no |
in most distributions |
ethtool |
reports on ethernet interface configuration |
yes |
yes |
iperf |
network bandwidth tool |
no |
yes |
tcptrace |
packet analysis tool |
no |
yes |
3.0 CPU簡介
CPU的利用率很大程度取決於運行什麼類型的任務。核心調度器服務於兩種任務:線程(單或多)和中斷。調度器賦予不同任務以不同的優先順序,下面是各個任務的優先順序排序:
- 中斷——裝置通知核心完成了某個操作。比如網卡發送了一個網路包或者某個硬體驅動產生了一個IO請求。
- 核心進程——所有的核心進程以此優先順序運行。
- 使用者進程——即通常所說的使用者態。所有的軟體應用以使用者態運行。在核心調度機制中,使用者態優先順序最低。
為了便於理解核心如何管理和調度這些任務,下面將介紹一些重點概念:環境切換、運行隊列及利用率。
3.1 環境切換
大部分現代處理器只能同時運行一個單線程進程或者一個線程。N路超執行緒或N核處理器則可以同時運行N個線程。其實Linux核心把多核處理器中的每一個核看成一個獨立的處理器,例如一個單一處理器雙核的系統在Linux核心看來就是一個雙處理器的系統。
一個標準的Linux核心支援“同時”運行50-50000個線程,如果只有一個CPU,核心必須公平地調度這些線程。每一個線程會被分配一個CPU時間片,一旦線程用完了該時間片或者被更高優先順序的任務(比如硬體中斷)搶佔,線程就會被放回運行隊列中,而更高優先順序的任務將佔用CPU。這種線程之間的切換被稱作為環境切換。
環境切換時,核心需要消耗一定的資源用於將線程從CPU寄存器移到運行隊列。因此,一個系統環境切換的次數越多,核心用以完成調度工作的額外消耗也就越多。
3.2 運行隊列
每一個CPU都維護了一個可運行狀態線程的隊列。理想狀況是調度器一直連續不間斷地在執行線程。線程一般要麼是在sleep狀態(被阻塞或者等待IO完成),要麼在可運行狀態。在CPU被過度使用時,核心調度器就可能不能立刻執行系統命令,而可啟動並執行線程就可能會充滿運行隊列。運行隊列越大,線程等待執行的時間就可能越長。
一個熟為人知的用於描述運行隊列狀態的詞叫做“負載”。系統的負載的值是正在執行的線程數和等待執行線程數之和。假設,一個雙核系統中正有兩個線程在執行,還有4個線程在運行隊列中等待執行,那麼這個系統當前的負載值就是6。Top命令可以統計1/5/15分鐘的系統負載均值(即load average)。
3.3 CPU利用率
CPU利用率,即CPU被使用的百分比。CPU的應用情況是衡量一個系統的重要指標。大部分效能監控工具會將CPU的使用分成如下幾類:
User Time——CPU用於執行使用者態線程的時間百分比
System Time——CPU用於執行核心線程和中斷的時間百分比
Wait IO——因為所有線程都在等待IO而CPU處於空閑狀態的時間百分比
Idle——CPU完全處於空閑狀態的時間百分比
譯註:Wait IO和Idle的相同點是線程運行隊列為空白,不同點是Wait IO是線程等待隊列非空而Idle是線程等待隊列也為空白。
4.0 CPU效能監控
CPU效能表現如何一般從三個方面來衡量:運行隊列、利用率和環境切換。正如前文所提及的,效能表現的好壞和基準資料(或預期)是密不可分的。對大部分系統而言,一些基本的效能預期如下:
- 運行隊列——每個處理器運行隊列中不應該超過1-3個線程。例如,一個雙核的系統中,運行隊列長度不應該超過6。(譯註:即一個系統的load average值不應該大於核心數的4倍。)
- CPU利用率——假如CPU被充分利用了,那麼必須達到以下的佔比劃分:
- User Time佔65%-70%
- System Time佔30%-35%
- Idle佔0%-5%
- 環境切換——環境切換的次數和CPU利用率相關。假設CPU利用率達到了上述的佔比劃分,大量的環境切換也是可以接受的。
Linux系統有很多工具可以用來統計這些指標。我們將首先來看vmstat和top。
4.1 vmstat工具的使用
vmstat帶來的額外效能開銷很小,因此,在一個高負載系統上一直運行該工具是可行的,即使你並不想長久地統計它的效能資料。該工具有兩種運行模式:統計模式和取樣模式。取樣模式每隔一個指定的時間間隔會統計和輸出一個結果。這種模式在統計一個持久負載下的效能資料時非常有用。下面是一個vmstat在指定時間間隔為1秒時的輸出樣本:
上面輸出中CPU相關各列的意義如下:
列名 |
含義 |
r |
運行隊列的長度,即等待執行的線程數目 |
b |
處於阻塞狀態或者等待IO完成狀態的線程數目 |
in |
系統中斷的數目 |
cs |
環境切換的數目 |
us |
CPU執行使用者態線程的時間佔比 |
sys |
CPU執行系統態線程佔用的時間佔比,包含核心和中斷兩部分 |
wa |
CPU處於等待狀態的時間佔比(CPU等待狀態即所有線程都處於被阻塞或者等待IO完成狀態) |
id |
CPU處於完全空閑狀態的時間佔比 |
4.2 案例分析:CPU的持續耗用
在下面的案例中,系統CPU已經被完全用盡。
從上面輸出,我們可以得出以下推論:
- 系統中有大量的中斷和少數的環境切換,看起來是某個進程正在請求訪問硬體裝置。
- CPU使用者態耗用佔了85%以上,同時只有少量的環境切換,進一步證明了有一個進程一直在佔用CPU。
- 運行隊列長度達到可以接受的上限,甚至在幾個瞬間已經超過了這個上限。
4.3 案例分析:調度器過載
在下面的案例中,核心調度器一直忙於環境切換。
從上面的輸出,我們可以得出以下推論:
- 環境切換的次數遠大於中斷的次數。核心必須消耗大量的時間用於環境切換。
- 大量的環境切換導致了CPU利用率的不平衡。從使用者態CPU佔用極低和Wait IO態CPU佔用極高可以明顯看出來。
- 因為CPU處於等待IO狀態,運行隊列開始堆積,等待IO的線程數也開始堆積。
4.4 mpstat工具的使用
如果系統有多個處理器核心,你可以使用mpstat命令來監控各個核。Linux核心把雙核處理器看作為兩個處理器。因此,一個雙核雙處理器系統會被認為有4個處理器。mpstat提供了vmstat類似的CPU統計功能,不過mpstat還按CPU核的粒度提供了統計資料。
4.5 案例分析:未充分使用的處理器負載
在下面的案例中,系統有4個CPU核心,有兩個CPU耗用型的進程將其中兩個核(CPU0和CPU1)充分利用,第三個核正在執行核心和系統調用(CPU3),第四個核(CPU2)處於空閑狀態。
Top命令顯示了有3個進程(nobody、mysql、apache)幾乎各自佔用了其中的一整個CPU核心:
你可以通過ps命令的PSR欄位判斷哪一個進程佔用了哪一個CPU核心。
4.6 結論
CPU的效能監控包含如下要點:
- 檢查運行隊列,保證每個處理器的運行隊列長度不超過3。
- 保證CPU的利用率在使用者態和系統態的比例在70/30和65/35之間。
- 如果CPU在系統態所花的時間更多,可能不僅僅是過載的原因,嘗試重新設定一下進程的優先順序
- 運行IO型的進程比運行CPU型的進程更有收益(譯註:是指在CPU利用率較高時?)
5.0 虛擬記憶體相關
虛擬記憶體使用磁碟作為記憶體的擴充,這樣可用的“記憶體”就更多了。在記憶體不夠時,核心會把最近沒有使用的記憶體塊寫到磁碟上去。當這部分記憶體再次被訪問時,會把這部分內容再從磁碟讀取到實體記憶體中。這些操作對使用者是完全透明的,Linux上的應用程式只是看到有大量的記憶體可用,但是不知道這些“記憶體”有部分是儲存在磁碟上的。毫無疑問,讀寫磁碟比讀寫真正的記憶體要慢得多(順序讀寫大概比記憶體慢1000倍),因此程式讀寫記憶體的時候,如果使用了大量的虛存,程式運行就慢了。磁碟作為虛存使用的那部分叫做交換空間/分區(swap space)。
5.1 虛存頁
虛存是按頁進行劃分的,X86架構上的虛存頁大小是4KB。核心進行虛存讀寫的時候,是按頁進行的。核心在某些時候會將記憶體頁寫到交換空間和檔案系統中。①
5.2 記憶體同步②(原文:kernel memory paging)
記憶體同步是一個常見的操作,不要和記憶體交換(頁置換)搞混淆了。定期將記憶體同步到磁碟的過程稱為記憶體映射。運行一段時間後,程式可能會慢慢將記憶體耗盡。在某個時刻,核心為了分配記憶體給其他程式(或者當前程式),可能需要將最近沒有使用的記憶體置換到磁碟上去,如果之前已經把記憶體同步到了磁碟上,此時swapping的操作效率就提高了(不需要在swap前將內容同步到磁碟了)。
5.3 記憶體回收機制
記憶體回收機制是為了擷取可用的實體記憶體,其挑選犧牲頁的演算法因內類型而異。一些頁類型如下:
Unreclaimable——鎖住的、核心使用的、保留的頁
Swappable——匿名記憶體頁,和交換分區相關的記憶體頁
Syncable——和檔案系統相關的記憶體頁
Discardable——靜態頁、已廢棄的頁
除了不可回收頁,其他類型頁都可能被回收。
記憶體回收主要的有兩大機制:kswapd和“Low on Memory Reclaim”。
5.4 kswapd
守護進程kswapd的作用是保證有一定的空閑記憶體可用。核心中有pages_high和pages_low兩個指標,如果可用記憶體低於pages_low,kswapd進程開始嘗試釋放記憶體,每次釋放32頁的記憶體直到可用記憶體高於pages_high。
kswapd會執行如下的操作:
- 如果頁面沒有修改,將該頁面放到空閑列表
- 如果頁面已修改且是和檔案系統相關的,將該頁面內容寫到磁碟 ③
- 如果頁面已修改且不是和檔案系統相關的(匿名頁,對應到交換分區),將該頁面內容寫到交換裝置
5.5 通過pdflush④完成記憶體同步(原文kernel paging with pdflush)
守護進程pdflush的作用是同步檔案系統相關的記憶體頁(Syncable)到磁碟。換句話說,當一個檔案的記憶體副本被修改時,pdflush會將修改寫回磁碟。
當記憶體中的髒頁⑤超過10%時,pdflush將同步這些髒頁到磁碟,10%這個參數值可由核心的vm.dirty_background_ratio調整。
絕大部分情況下,pdflush和記憶體回收機制是相互獨立的。當核心調用Low on Memory Reclaim時,除了其他釋放記憶體的操作,LMR還調用pdflush來同步到期頁。
5.6 案例分析:
vmstat工具在統計CPU使用的同時也統計了虛存的使用方式。下面是vmstat輸出中和虛存相關的一些指標:
列名 |
含義 |
swpd |
當前使用的虛存數量,單位KB。當空閑記憶體達到下限時,會有更多的資料被置換到交換分區。 |
free |
RAM當前的可用記憶體,單位KB。 |
buff |
實體記憶體作為read()和write()操作緩衝區部分的大小,單位KB。⑥ |
cache |
實體記憶體映射到進程地址空間的大小,單位KB。⑥ |
so |
寫到交換分區的資料量,單位KB |
si |
從交換分區寫到RAM的資料量,單位KB |
bo |
RAM中置換到檔案系統或者交換分區的磁碟塊數量 |
bi |
從檔案系統或者交換分區置換到RAM中的磁碟塊的數量 |
下面vmstat的輸出,可以看出在一個IO型應用的尖峰時刻,有大量的虛存使用:
從上面的輸出中,我們可以得到以下推論:
大量的磁碟塊(bi)從檔案系統交換到了記憶體中。這個可以通過cache的增長明顯看出來。
在最後這段時間內,儘管資料從磁碟交換到記憶體中耗用了RAM,但空閑記憶體(free)一直保持在17MB。
為了維持可用的空閑記憶體,kswapd挪用了讀寫緩衝(buff),並將這些記憶體加入到空閑記憶體表中。這個可以從buff的減少看出來。
然後kswapd進程將一些髒頁寫到交換空間(so),這個也可以通過虛存使用(swpd)的增長看出來。
5.7 結論
虛存的效能監控,一般包括以下幾點:
- 大缺頁越少,回應時間就更快。因為此時系統在使用記憶體而不是磁碟。
- 空閑記憶體較低是一個好的現象,表明了緩衝正被高效使用,除非同時伴有持續的寫交換分區的操作。
- 如果一個系統持續在操作交換分區,表明這個系統記憶體告緊。
譯註:
①記憶體寫到檔案系統:比如在釋放記憶體作為buffer使用的部分,需要將記憶體內容寫到檔案系統;記憶體寫到交換分區:比如將實存置換到虛存的時候。
②原文中的memory paging指的應該不是記憶體分頁機制,根據上下文指的應該是記憶體到磁碟的同步,譯文中翻譯為記憶體同步
③和檔案系統相關的記憶體頁,可能是記憶體中的buffer或cache部分。記憶體映射到swap file的部分,不確定是和檔案系統相關還是和交換分區相關
④kswapd和pdflush的異同和關聯:
相同點:兩者都會把記憶體資料寫到磁碟上
不同點:兩者把記憶體資料寫到磁碟的目的不同:kswapd是為了釋放記憶體,但釋放記憶體前需要先把這部分資料暫存到磁碟上;pdflush是為了同步記憶體和磁碟的資料。
關聯:正如5.2提到的,pdflush操作會提高kswapd的效率。
⑤原文叫dirty page,一般翻譯為髒頁,是指緩衝比對應的磁碟內容要新的記憶體頁。
⑥原文這裡對於的buffer和cache的解釋,和很多資料查到的不一致,個人覺得原文這裡的解釋有點不妥。
buffer:記憶體用於緩衝磁碟塊以及檔案中繼資料的部分,這部分資料可以通過塊裝置和塊號直接存取
cache:記憶體用於快取檔案資料的部分,主要通過inode訪問