1. 程式人生 > >Linux 效能監測:工具

Linux 效能監測:工具

一個完整執行的 Linux 系統包括很多子系統(介紹CPUMemoryIONetwork,…),監測和評估這些子系統是效能監測的一部分。我們往往需要巨集觀的看整個系統狀態,也需要微觀的看每個子系統的執行情況。幸運的是,我們不必重複造輪子,監控這些子系統都有相應的工具可用,這些經過時間考驗、隨 Unix 成長起來、簡單而優雅的小工具是我們日常 Unix/Linux 工作不可缺少的部分。

下面這張圖片很好的總結了 Linux 各個子系統以及監控這些子系統所需要的工具,如果你對 Linux 系統管理(sysadmin & devops)感興趣、想入門的話,可以從這張圖開始慢慢了解和熟悉各個工具。對於熟練的 Linux 屌絲,這張圖你應該能問答自如。(圖片來自:

Linux Performance Analysis and Tools,幻燈片也很精彩,建議對照閱讀。)

linux performance analysis and tools

看了某某教程、讀了某某手冊,按照要求改改某某設定、系統設定、核心引數就認為做到系統優化的想法很傻很天真:)系統優化是一項複雜、繁瑣、長期的工作,優化前需要監測、採集、測試、評估,優化後也需要測試、採集、評估、監測,而且是一個長期和持續的過程,不是說現在優化了,測試了,以後就可以一勞永逸了,也不是說書本上的優化就適合眼下正在執行的系統,不同的系統、不同的硬體、不同的應用優化的重點也不同、優化的方法也不同、優化的引數也不同。效能監測是系統優化過程中重要的一環,如果沒有監測、不清楚效能瓶頸在哪裡,優化什麼呢、怎麼優化呢?所以找到效能瓶頸是效能監測的目的,也是系統優化的關鍵。系統由若干子系統構成,通常修改一個子系統有可能影響到另外一個子系統,甚至會導致整個系統不穩定、崩潰。所以說優化、監測、測試通常是連在一起的,而且是一個迴圈而且長期的過程,通常監測的子系統有以下這些:

  • CPU
  • Memory
  • IO
  • Network

這些子系統互相依賴,瞭解這些子系統的特性,監測這些子系統的效能引數以及及時發現可能會出現的瓶頸對系統優化很有幫助。

應用型別

不同的系統用途也不同,要找到效能瓶頸需要知道系統跑的是什麼應用、有些什麼特點,比如 web server 對系統的要求肯定和 file server 不一樣,所以分清不同系統的應用型別很重要,通常應用可以分為兩種型別:

  • IO 相關,IO 相關的應用通常用來處理大量資料,需要大量記憶體和儲存,頻繁 IO 操作讀寫資料,而對 CPU 的要求則較少,大部分時候 CPU 都在等待硬碟,比如,資料庫伺服器、檔案伺服器等。
  • CPU 相關,CPU 相關的應用需要使用大量 CPU,比如高併發的 web/mail 伺服器、影象/視訊處理、科學計算等都可被視作 CPU 相關的應用。

看看實際中的例子,第1個是檔案伺服器拷貝一個大檔案時表現出來的特徵,第2個是 CPU 做大量計算時表現出來的特徵:

$ 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
 0  4    140 1962724 335516 4852308  0    0   388 65024 1442  563  0  2 47 52  0
 0  4    140 1961816 335516 4853868  0    0   768 65536 1434  522  0  1 50 48  0
 0  4    140 1960788 335516 4855300  0    0   768 48640 1412  573  0  1 50 49  0
 0  4    140 1958528 335516 4857280  0    0  1024 65536 1415  521  0  1 41 57  0
 0  5    140 1957488 335516 4858884  0    0   768 81412 1504  609  0  2 50 49  0
$ 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
 4  0    140 3625096 334256 3266584  0    0     0    16 1054  470 100 0  0  0  0
 4  0    140 3625220 334264 3266576  0    0     0    12 1037  448 100 0  0  0  0
 4  0    140 3624468 334264 3266580  0    0     0   148 1160  632 100 0  0  0  0
 4  0    140 3624468 334264 3266580  0    0     0     0 1078  527 100 0  0  0  0
 4  0    140 3624712 334264 3266580  0    0     0    80 1053  501 100 0  0  0  0

上面兩個例子最明顯的差別就是 id 一欄,代表 CPU 的空閒率,拷貝檔案時候 id 維持在 50% 左右,CPU 大量計算的時候 id 基本為 0。

底線

我們如何知道系統性能是好還是差呢?這需要事先建立一個底線,如果效能監測得到的統計資料跨過這條線,我們就可以說這個系統性能差,如果資料能保持線上內我們就說效能好。建立這樣底線需要知道一些理論、額外的負載測試和系統管理員多年的經驗。如果自己沒有多年的經驗,有一個簡單劃底線的辦法就是:把這個底線建立在自己對系統的期望上。自己期望這個系統有個什麼樣的效能,這是一個底線,如果沒有達到這個要求就是效能差。比如,VPSee 上個月有個 RAID0 的測試,期望的測試結果應該是 RAID0 的 IO 效能比單硬碟有顯著提高,底線是 RAID0 的 IO 至少要比單硬碟要好(好多少不重要,底線是至少要好),測試結果卻發現 RAID0 效能還不如單硬碟,說明效能差,這個時候需要問個為什麼,這往往是效能瓶頸所在,經過排查發現是原硬碟有硬體瑕疵造成效能測試結果錯誤。

監測工具

我們只需要簡單的工具就可以對 Linux 的效能進行監測,以下是 VPSee 常用的工具:

工具 簡單介紹
top 檢視程序活動狀態以及一些系統狀況
vmstat 檢視系統狀態、硬體和系統資訊等
iostat 檢視CPU 負載,硬碟狀況
sar 綜合工具,檢視系統狀況
mpstat 檢視多處理器狀況
netstat 檢視網路狀況
iptraf 實時網路狀況監測
tcpdump 抓取網路資料包,詳細分析
tcptrace 資料包分析工具
netperf 網路頻寬工具
dstat 綜合工具,綜合了 vmstat, iostat, ifstat, netstat 等多個資訊

接下來幾天,VPSee 將會陸續介紹一些 Linux 效能監測方面的經驗。

linux-cpu

CPU 的佔用主要取決於什麼樣的資源正在 CPU 上面執行,比如拷貝一個檔案通常佔用較少 CPU,因為大部分工作是由 DMA(Direct Memory Access)完成,只是在完成拷貝以後給一箇中斷讓 CPU 知道拷貝已經完成;科學計算通常佔用較多的 CPU,大部分計算工作都需要在 CPU 上完成,記憶體、硬碟等子系統只做暫時的資料儲存工作。要想監測和理解 CPU 的效能需要知道一些的作業系統的基本知識,比如:中斷、程序排程、程序上下文切換、可執行佇列等。這裡 VPSee 用個例子來簡單介紹一下這些概念和他們的關係,CPU 很無辜,是個任勞任怨的打工仔,每時每刻都有工作在做(程序、執行緒)並且自己有一張工作清單(可執行佇列),由老闆(程序排程)來決定他該幹什麼,他需要和老闆溝通以便得到老闆的想法並及時調整自己的工作(上下文切換),部分工作做完以後還需要及時向老闆彙報(中斷),所以打工仔(CPU)除了做自己該做的工作以外,還有大量時間和精力花在溝通和彙報上。

CPU 也是一種硬體資源,和任何其他硬體裝置一樣也需要驅動和管理程式才能使用,我們可以把核心的程序排程看作是 CPU 的管理程式,用來管理和分配 CPU 資源,合理安排程序搶佔 CPU,並決定哪個程序該使用 CPU、哪個程序該等待。作業系統核心裡的程序排程主要用來排程兩類資源:程序(或執行緒)和中斷,程序排程給不同的資源分配了不同的優先順序,優先順序最高的是硬體中斷,其次是核心(系統)程序,最後是使用者程序。每個 CPU 都維護著一個可執行佇列,用來存放那些可執行的執行緒。執行緒要麼在睡眠狀態(blocked 正在等待 IO)要麼在可執行狀態,如果 CPU 當前負載太高而新的請求不斷,就會出現程序排程暫時應付不過來的情況,這個時候就不得不把執行緒暫時放到可執行佇列裡。VPSee 在這裡要討論的是效能監測,上面談了一堆都沒提到效能,那麼這些概念和效能監測有什麼關係呢?關係重大。如果你是老闆,你如何檢查打工仔的效率(效能)呢?我們一般會通過以下這些資訊來判斷打工仔是否偷懶:

  • 打工仔接受和完成多少任務並向老闆彙報了(中斷);
  • 打工仔和老闆溝通、協商每項工作的工作進度(上下文切換);
  • 打工仔的工作列表是不是都有排滿(可執行佇列);
  • 打工仔工作效率如何,是不是在偷懶(CPU 利用率)。

現在把打工仔換成 CPU,我們可以通過檢視這些重要引數:中斷、上下文切換、可執行佇列、CPU 利用率來監測 CPU 的效能。

底線

上一篇 Linux 效能監測:介紹 提到了效能監測前需要知道底線,那麼監測 CPU 效能的底線是什麼呢?通常我們期望我們的系統能到達以下目標:

  • CPU 利用率,如果 CPU 有 100% 利用率,那麼應該到達這樣一個平衡:65%-70% User Time,30%-35% System Time,0%-5% Idle Time;
  • 上下文切換,上下文切換應該和 CPU 利用率聯絡起來看,如果能保持上面的 CPU 利用率平衡,大量的上下文切換是可以接受的;
  • 可執行佇列,每個可執行佇列不應該超過3個執行緒(每處理器),比如:雙處理器系統的可執行佇列裡不應該超過6個執行緒。

vmstat

vmstat 是個檢視系統整體效能的小工具,小巧、即使在很 heavy 的情況下也執行良好,並且可以用時間間隔採集得到連續的效能資料。

$ 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
 2  1    140 2787980 336304 3531996  0    0     0   128 1166 5033  3  3 70 25  0
 0  1    140 2788296 336304 3531996  0    0     0     0 1194 5605  3  3 69 25  0
 0  1    140 2788436 336304 3531996  0    0     0     0 1249 8036  5  4 67 25  0
 0  1    140 2782688 336304 3531996  0    0     0     0 1333 7792  6  6 64 25  0
 3  1    140 2779292 336304 3531992  0    0     0    28 1323 7087  4  5 67 25  0

引數介紹:

  • r,可執行佇列的執行緒數,這些執行緒都是可執行狀態,只不過 CPU 暫時不可用;
  • b,被 blocked 的程序數,正在等待 IO 請求;
  • in,被處理過的中斷數
  • cs,系統上正在做上下文切換的數目
  • us,使用者佔用 CPU 的百分比
  • sy,核心和中斷佔用 CPU 的百分比
  • wa,所有可執行的執行緒被 blocked 以後都在等待 IO,這時候 CPU 空閒的百分比
  • id,CPU 完全空閒的百分比

舉兩個現實中的例子來實際分析一下:

$ 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
 4  0    140 2915476 341288 3951700  0    0     0     0 1057  523 19 81  0  0  0
 4  0    140 2915724 341296 3951700  0    0     0     0 1048  546 19 81  0  0  0
 4  0    140 2915848 341296 3951700  0    0     0     0 1044  514 18 82  0  0  0
 4  0    140 2915848 341296 3951700  0    0     0    24 1044  564 20 80  0  0  0
 4  0    140 2915848 341296 3951700  0    0     0     0 1060  546 18 82  0  0  0

從上面的資料可以看出幾點:

  1. interrupts(in)非常高,context switch(cs)比較低,說明這個 CPU 一直在不停的請求資源;
  2. system time(sy)一直保持在 80% 以上,而且上下文切換較低(cs),說明某個程序可能一直霸佔著 CPU(不斷請求資源);
  3. run queue(r)剛好在4個。
$ 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
14  0    140 2904316 341912 3952308  0    0     0   460 1106 9593 36 64  1  0  0
17  0    140 2903492 341912 3951780  0    0     0     0 1037 9614 35 65  1  0  0
20  0    140 2902016 341912 3952000  0    0     0     0 1046 9739 35 64  1  0  0
17  0    140 2903904 341912 3951888  0    0     0    76 1044 9879 37 63  0  0  0
16  0    140 2904580 341912 3952108  0    0     0     0 1055 9808 34 65  1  0  0

從上面的資料可以看出幾點:

  1. context switch(cs)比 interrupts(in)要高得多,說明核心不得不來回切換程序;
  2. 進一步觀察發現 system time(sy)很高而 user time(us)很低,而且加上高頻度的上下文切換(cs),說明正在執行的應用程式呼叫了大量的系統呼叫(system call);
  3. run queue(r)在14個執行緒以上,按照這個測試機器的硬體配置(四核),應該保持在12個以內。

mpstat

mpstat 和 vmstat 類似,不同的是 mpstat 可以輸出多個處理器的資料,下面的輸出顯示 CPU1 和 CPU2 基本上沒有派上用場,系統有足夠的能力處理更多的任務。

$ mpstat -P ALL 1
Linux 2.6.18-164.el5 (vpsee) 	11/13/2009

02:24:33 PM  CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s
02:24:34 PM  all    5.26    0.00    4.01   25.06    0.00    0.00    0.00   65.66   1446.00
02:24:34 PM    0    7.00    0.00    8.00    0.00    0.00    0.00    0.00   85.00   1001.00
02:24:34 PM    1   13.00    0.00    8.00    0.00    0.00    0.00    0.00   79.00    444.00
02:24:34 PM    2    0.00    0.00    0.00  100.00    0.00    0.00    0.00    0.00      0.00
02:24:34 PM    3    0.99    0.00    0.99    0.00    0.00    0.00    0.00   98.02      0.00

ps

如何檢視某個程式、程序佔用了多少 CPU 資源呢?下面是 Firefox 在 VPSee 的一臺 Sunray 伺服器上的執行情況,當前只有2個使用者在使用 Firefox:

$ while :; do ps -eo pid,ni,pri,pcpu,psr,comm | grep 'firefox'; sleep 1; done

  PID  NI PRI %CPU PSR COMMAND
 7252   0  24  3.2   3 firefox
 9846   0  24  8.8   0 firefox
 7252   0  24  3.2   2 firefox
 9846   0  24  8.8   0 firefox
 7252   0  24  3.2   2 firefox

這裡的講到的 “記憶體” 包括實體記憶體和虛擬記憶體,虛擬記憶體(Virtual Memory)把計算機的記憶體空間擴充套件到硬碟,實體記憶體(RAM)和硬碟的一部分空間(SWAP)組合在一起作為虛擬記憶體為計算機提供了一個連貫的虛擬記憶體空間,好處是我們擁有的記憶體 ”變多了“,可以執行更多、更大的程式,壞處是把部分硬碟當記憶體用整體效能受到影響,硬碟讀寫速度要比記憶體慢幾個數量級,並且 RAM 和 SWAP 之間的交換增加了系統的負擔。

在作業系統裡,虛擬記憶體被分成頁,在 x86 系統上每個頁大小是 4KB。Linux 核心讀寫虛擬記憶體是以 “頁” 為單位操作的,把記憶體轉移到硬碟交換空間(SWAP)和從交換空間讀取到記憶體的時候都是按頁來讀寫的。記憶體和 SWAP 的這種交換過程稱為頁面交換(Paging),值得注意的是 paging 和 swapping 是兩個完全不同的概念,國內很多參考書把這兩個概念混為一談,swapping 也翻譯成交換,在作業系統裡是指把某程式完全交換到硬碟以騰出記憶體給新程式使用,和 paging 只交換程式的部分(頁面)是兩個不同的概念。純粹的 swapping 在現代作業系統中已經很難看到了,因為把整個程式交換到硬碟的辦法既耗時又費力而且沒必要,現代作業系統基本都是 paging 或者 paging/swapping 混合,swapping 最初是在 Unix system V 上實現的。

虛擬記憶體管理是 Linux 核心裡面最複雜的部分,要弄懂這部分內容可能需要一整本書的講解。VPSee 在這裡只介紹和效能監測有關的兩個核心程序:kswapd 和 pdflush。

  • kswapd daemon 用來檢查 pages_high 和 pages_low,如果可用記憶體少於 pages_low,kswapd 就開始掃描並試圖釋放 32個頁面,並且重複掃描釋放的過程直到可用記憶體大於 pages_high 為止。掃描的時候檢查3件事:1)如果頁面沒有修改,把頁放到可用記憶體列表裡;2)如果頁面被檔案系統修改,把頁面內容寫到磁碟上;3)如果頁面被修改了,但不是被檔案系統修改的,把頁面寫到交換空間。
  • pdflush daemon 用來同步檔案相關的記憶體頁面,把記憶體頁面及時同步到硬碟上。比如開啟一個檔案,檔案被匯入到記憶體裡,對檔案做了修改後並儲存後,核心並不馬上儲存檔案到硬碟,由 pdflush 決定什麼時候把相應頁面寫入硬碟,這由一個核心引數 vm.dirty_background_ratio 來控制,比如下面的引數顯示髒頁面(dirty pages)達到所有記憶體頁面10%的時候開始寫入硬碟。
# /sbin/sysctl -n vm.dirty_background_ratio
10

vmstat

繼續 vmstat 一些引數的介紹,上一篇 Linux 效能監測:CPU 介紹了 vmstat 的部分引數,這裡介紹另外一部分。以下資料來自 VPSee 的一個 256MB RAM,512MB SWAP 的 Xen VPS:

# 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
 0  3 252696   2432    268   7148 3604 2368  3608  2372  288  288  0  0 21 78  1
 0  2 253484   2216    228   7104 5368 2976  5372  3036  930  519  0  0  0 100  0
 0  1 259252   2616    128   6148 19784 18712 19784 18712 3821 1853  0  1  3 95  1
 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0
 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0  4
  • swpd,已使用的 SWAP 空間大小,KB 為單位;
  • free,可用的實體記憶體大小,KB 為單位;
  • buff,實體記憶體用來快取讀寫操作的 buffer 大小,KB 為單位;
  • cache,實體記憶體用來快取程序地址空間的 cache 大小,KB 為單位;
  • si,資料從 SWAP 讀取到 RAM(swap in)的大小,KB 為單位;
  • so,資料從 RAM 寫到 SWAP(swap out)的大小,KB 為單位;
  • bi,磁碟塊從檔案系統或 SWAP 讀取到 RAM(blocks in)的大小,block 為單位;
  • bo,磁碟塊從 RAM 寫到檔案系統或 SWAP(blocks out)的大小,block 為單位;

上面是一個頻繁讀寫交換區的例子,可以觀察到以下幾點:

  • 物理可用記憶體 free 基本沒什麼顯著變化,swapd 逐步增加,說明最小可用的記憶體始終保持在 256MB X 10% = 2.56MB 左右,當髒頁達到10%的時候(vm.dirty_background_ratio = 10)就開始大量使用 swap;
  • buff 穩步減少說明系統知道記憶體不夠了,kwapd 正在從 buff 那裡借用部分記憶體;
  • kswapd 持續把髒頁面寫到 swap 交換區(so),並且從 swapd 逐漸增加看出確實如此。根據上面講的 kswapd 掃描時檢查的三件事,如果頁面被修改了,但不是被檔案系統修改的,把頁面寫到 swap,所以這裡 swapd 持續增加。
liunx-io

磁碟通常是計算機最慢的子系統,也是最容易出現效能瓶頸的地方,因為磁碟離 CPU 距離最遠而且 CPU 訪問磁碟要涉及到機械操作,比如轉軸、尋軌等。訪問硬碟和訪問記憶體之間的速度差別是以數量級來計算的,就像1天和1分鐘的差別一樣。要監測 IO 效能,有必要了解一下基本原理和 Linux 是如何處理硬碟和記憶體之間的 IO 的。

記憶體頁

上一篇 Linux 效能監測:Memory 提到了記憶體和硬碟之間的 IO 是以頁為單位來進行的,在 Linux 系統上1頁的大小為 4K。可以用以下命令檢視系統預設的頁面大小:

$ /usr/bin/time -v date
	...
	Page size (bytes): 4096
	...

缺頁中斷

Linux 利用虛擬記憶體極大的擴充套件了程式地址空間,使得原來實體記憶體不能容下的程式也可以通過記憶體和硬碟之間的不斷交換(把暫時不用的記憶體頁交換到硬碟,把需要的記憶體頁從硬碟讀到記憶體)來贏得更多的記憶體,看起來就像實體記憶體被擴大了一樣。事實上這個過程對程式是完全透明的,程式完全不用理會自己哪一部分、什麼時候被交換進記憶體,一切都有核心的虛擬記憶體管理來完成。當程式啟動的時候,Linux 核心首先檢查 CPU 的快取和實體記憶體,如果資料已經在記憶體裡就忽略,如果資料不在記憶體裡就引起一個缺頁中斷(Page Fault),然後從硬碟讀取缺頁,並把缺頁快取到實體記憶體裡。缺頁中斷可分為主缺頁中斷(Major Page Fault)和次缺頁中斷(Minor Page Fault),要從磁碟讀取資料而產生的中斷是主缺頁中斷;資料已經被讀入記憶體並被快取起來,從記憶體快取區中而不是直接從硬碟中讀取資料而產生的中斷是次缺頁中斷。

上面的記憶體快取區起到了預讀硬碟的作用,核心先在實體記憶體裡尋找缺頁,沒有的話產生次缺頁中斷從記憶體快取裡找,如果還沒有發現的話就從硬碟讀取。很顯然,把多餘的記憶體拿出來做成記憶體快取區提高了訪問速度,這裡還有一個命中率的問題,運氣好的話如果每次缺頁都能從記憶體快取區讀取的話將會極大提高效能。要提高命中率的一個簡單方法就是增大記憶體快取區面積,快取區越大預存的頁面就越多,命中率也會越高。下面的 time 命令可以用來檢視某程式第一次啟動的時候產生了多少主缺頁中斷和次缺頁中斷:

$ /usr/bin/time -v date
	...
	Major (requiring I/O) page faults: 1
	Minor (reclaiming a frame) page faults: 260
	...

File Buffer Cache

從上面的記憶體快取區(也叫檔案快取區 File Buffer Cache)讀取頁比從硬碟讀取頁要快得多,所以 Linux 核心希望能儘可能產生次缺頁中斷(從檔案快取區讀),並且能儘可能避免主缺頁中斷(從硬碟讀),這樣隨著次缺頁中斷的增多,檔案快取區也逐步增大,直到系統只有少量可用實體記憶體的時候 Linux 才開始釋放一些不用的頁。我們執行 Linux 一段時間後會發現雖然系統上執行的程式不多,但是可用記憶體總是很少,這樣給大家造成了 Linux 對記憶體管理很低效的假象,事實上 Linux 把那些暫時不用的實體記憶體高效的利用起來做預存(記憶體快取區)呢。下面列印的是 VPSee 的一臺 Sun 伺服器上的實體記憶體和檔案快取區的情況:

$ cat /proc/meminfo
MemTotal:      8182776 kB
MemFree:       3053808 kB
Buffers:        342704 kB
Cached:        3972748 kB

這臺伺服器總共有 8GB 實體記憶體(MemTotal),3GB 左右可用記憶體(MemFree),343MB 左右用來做磁碟快取(Buffers),4GB 左右用來做檔案快取區(Cached),可見 Linux 真的用了很多實體記憶體做 Cache,而且這個快取區還可以不斷增長。

頁面型別

Linux 中記憶體頁面有三種類型:

  • Read pages,只讀頁(或內碼表),那些通過主缺頁中斷從硬碟讀取的頁面,包括不能修改的靜態檔案、可執行檔案、庫檔案等。當核心需要它們的時候把它們讀到記憶體中,當記憶體不足的時候,核心就釋放它們到空閒列表,當程式再次需要它們的時候需要通過缺頁中斷再次讀到記憶體。
  • Dirty pages,髒頁,指那些在記憶體中被修改過的資料頁,比如文字檔案等。這些檔案由 pdflush 負責同步到硬碟,記憶體不足的時候由 kswapd 和 pdflush 把資料寫回硬碟並釋放記憶體。
  • Anonymous pages,匿名頁,那些屬於某個程序但是又和任何檔案無關聯,不能被同步到硬碟上,記憶體不足的時候由 kswapd 負責將它們寫到交換分割槽並釋放記憶體。

IO’s Per Second(IOPS)

每次磁碟 IO 請求都需要一定的時間,和訪問記憶體比起來這個等待時間簡直難以忍受。在一臺 2001 年的典型 1GHz PC 上,磁碟隨機訪問一個 word 需要 8,000,000 nanosec = 8 millisec,順序訪問一個 word 需要 200 nanosec;而從記憶體訪問一個 word 只需要 10 nanosec.(資料來自:Teach Yourself Programming in Ten Years)這個硬碟可以提供 125 次 IOPS(1000 ms / 8 ms)。

順序 IO 和 隨機 IO

IO 可分為順序 IO 和 隨機 IO 兩種,效能監測前需要弄清楚系統偏向順序 IO 的應用還是隨機 IO 應用。順序 IO 是指同時順序請求大量資料,比如資料庫執行大量的查詢、流媒體服務等,順序 IO 可以同時很快的移動大量資料。可以這樣來評估 IOPS 的效能,用每秒讀寫 IO 位元組數除以每秒讀寫 IOPS 數,rkB/s 除以 r/s,wkB/s 除以 w/s. 下面顯示的是連續2秒的 IO 情況,可見每次 IO 寫的資料是增加的(45060.00 / 99.00 = 455.15 KB per IO,54272.00 / 112.00 = 484.57 KB per IO)。相對隨機 IO 而言,順序 IO 更應該重視每次 IO 的吞吐能力(KB per IO):

$ iostat -kx 1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    2.50   25.25    0.00   72.25

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb       24.00 19995.00 29.00 99.00  4228.00 45060.00   770.12    45.01  539.65   7.80  99.80

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.00    0.00    1.00   30.67    0.00   68.33

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        3.00 12235.00  3.00 112.00   768.00 54272.00   957.22   144.85  576.44   8.70 100.10

隨機 IO 是指隨機請求資料,其 IO 速度不依賴於資料的大小和排列,依賴於磁碟的每秒能 IO 的次數,比如 Web 服務、Mail 服務等每次請求的資料都很小,隨機 IO 每秒同時會有更多的請求數產生,所以磁碟的每秒能 IO 多少次是關鍵。

$ iostat -kx 1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.75    0.00    0.75    0.25    0.00   97.26

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        0.00    52.00  0.00 57.00     0.00   436.00    15.30     0.03    0.54   0.23   1.30

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.75    0.00    0.75    0.25    0.00   97.24

Device:  rrqm/s   wrqm/s   r/s   w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
sdb        0.00    56.44  0.00 66.34     0.00   491.09    14.81     0.04    0.54   0.19   1.29

按照上面的公式得出:436.00 / 57.00 = 7.65 KB per IO,491.09 / 66.34 = 7.40 KB per IO. 與順序 IO 比較發現,隨機 IO 的 KB per IO 小到可以忽略不計,可見對於隨機 IO 而言重要的是每秒能 IOPS 的次數,而不是每次 IO 的吞吐能力(KB per IO)。

SWAP

當系統沒有足夠實體記憶體來應付所有請求的時候就會用到 swap 裝置,swap 裝置可以是一個檔案,也可以是一個磁碟分割槽。不過要小心的是,使用 swap 的代價非常大。如果系統沒有實體記憶體可用,就會頻繁 swapping,如果 swap 裝置和程式正要訪問的資料在同一個檔案系統上,那會碰到嚴重的 IO 問題,最終導致整個系統遲緩,甚至崩潰。swap 裝置和記憶體之間的 swapping 狀況是判斷 Linux 系統性能的重要參考,我們已經有很多工具可以用來監測 swap 和 swapping 情況,比如:top、cat /proc/meminfo、vmstat 等:

$ cat /proc/meminfo 
MemTotal:      8182776 kB
MemFree:       2125476 kB
Buffers:        347952 kB
Cached:        4892024 kB
SwapCached:        112 kB
...
SwapTotal:     4096564 kB
SwapFree:      4096424 kB
...

$ 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
 1  2 260008   2188    144   6824 11824 2584 12664  2584 1347 1174 14  0  0 86  0
 2  1 262140   2964    128   5852 24912 17304 24952 17304 4737 2341 86 10  0  0  4
linux-network

網路的監測是所有 Linux 子系統裡面最複雜的,有太多的因素在裡面,比如:延遲、阻塞、衝突、丟包等,更糟的是與 Linux 主機相連的路由器、交換機、無線訊號都會影響到整體網路並且很難判斷是因為 Linux 網路子系統的問題還是別的裝置的問題,增加了監測和判斷的複雜度。現在我們使用的所有網絡卡都稱為自適應網絡卡,意思是說能根據網路上的不同網路裝置導致的不同網路速度和工作模式進行自動調整。我們可以通過 ethtool 工具來檢視網絡卡的配置和工作模式:

# /sbin/ethtool eth0
Settings for eth0:
	Supported ports: [ TP ]
	Supported link modes:   10baseT/Half 10baseT/Full 
	                        100baseT/Half 100baseT/Full 
	                        1000baseT/Half 1000baseT/Full 
	Supports auto-negotiation: Yes
	Advertised link modes:  10baseT/Half 10baseT/Full 
	                        100baseT/Half 100baseT/Full 
	                        1000baseT/Half 1000baseT/Full 
	Advertised auto-negotiation: Yes
	Speed: 100Mb/s
	Duplex: Full
	Port: Twisted Pair
	PHYAD: 1
	Transceiver: internal
	Auto-negotiation: on
	Supports Wake-on: g
	Wake-on: g
	Current message level: 0x000000ff (255)
	Link detected: yes

上面給出的例子說明網絡卡有 10baseT,100baseT 和 1000baseT 三種選擇,目前正自適應為 100baseT(Speed: 100Mb/s)。可以通過 ethtool 工具強制網絡卡工作在 1000baseT 下:

# /sbin/ethtool -s eth0 speed 1000 duplex full autoneg off

iptraf

兩臺主機之間有網線(或無線)、路由器、交換機等裝置,測試兩臺主機之間的網路效能的一個辦法就是在這兩個系統之間互發資料並統計結果,看看吞吐量、延遲、速率如何。iptraf 就是一個很好的檢視本機網路吞吐量的好工具,支援文字圖形介面,很直觀。下面圖片顯示在 100 mbps 速率的網路下這個 Linux 系統的傳送傳輸率有點慢,Outgoing rates 只有 66 mbps.

# iptraf -d eth0

linux system performance monitoring: network

netperf

netperf 執行在 client/server 模式下,比 iptraf 能更多樣化的測試終端的吞吐量。先在伺服器端啟動 netserver:

# netserver 
Starting netserver at port 12865
Starting netserver at hostname 0.0.0.0 port 12865 and family AF_UNSPEC

然後在客戶端測試伺服器,執行一次持續10秒的 TCP 測試:

# netperf -H 172.16.38.36 -l 10
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Recv   Send    Send                          
Socket Socket  Message  Elapsed              
Size   Size    Size     Time     Throughput  
bytes  bytes   bytes    secs.    10^6bits/sec  

 87380  16384  16384    10.32      93.68

從以上輸出可以看出,網路吞吐量在 94mbps 左右,對於 100mbps 的網路來說這個效能算的上很不錯。上面的測試是在伺服器和客戶端位於同一個區域網,並且區域網是有線網的情況,你也可以試試不同結構、不同速率的網路,比如:網路之間中間多幾個路由器、客戶端在 wi-fi、VPN 等情況。

netperf 還可以通過建立一個 TCP 連線並順序地傳送資料包來測試每秒有多少 TCP 請求和響應。下面的輸出顯示在 TCP requests 使用 2K 大小,responses 使用 32K 的情況下處理速率為每秒243:

# netperf -t TCP_RR -H 172.16.38.36 -l 10 -- -r 2048,32768
TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.38.36 (172.16.38.36) port 0 AF_INET
Local /Remote
Socket Size   Request  Resp.   Elapsed  Trans.
Send   Recv   Size     Size    Time     Rate         
bytes  Bytes  bytes    bytes   secs.    per sec   

16384  87380  2048     32768   10.00     243.03   
16384  87380 

iperf

iperf 和 netperf 執行方式類似,也是 server/client 模式,先在伺服器端啟動 iperf:

# iperf -s -D
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
Running Iperf Server as a daemon
The Iperf daemon process ID : 5695

然後在客戶端對伺服器進行測試,客戶端先連線到伺服器端(172.16.38.36),並在30秒內每隔5秒對伺服器和客戶端之間的網路進行一次頻寬測試和取樣:

# iperf -c 172.16.38.36 -t 30 -i 5
------------------------------------------------------------
Client connecting to 172.16.38.36, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  3] local 172.16.39.100 port 49515 connected with 172.16.38.36 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0- 5.0 sec  58.8 MBytes  98.6 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  5.0-10.0 sec  55.0 MBytes  92.3 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 10.0-15.0 sec  55.1 MBytes  92.4 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 15.0-20.0 sec  55.9 MBytes  93.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 20.0-25.0 sec  55.4 MBytes  92.9 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3] 25.0-30.0 sec  55.3 MBytes  92.8 Mbits/sec
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.0 sec    335 MBytes  93.7 Mbits/sec

tcpdump 和 tcptrace

tcmdump 和 tcptrace 提供了一種更細緻的分析方法,先用 tcpdump 按要求捕獲資料包把結果輸出到某一檔案,然後再用 tcptrace 分析其檔案格式。這個工具組合可以提供一些難以用其他工具發現的資訊:

# /usr/sbin/tcpdump -w network.dmp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
511942 packets captured
511942 packets received by filter
0 packets dropped by kernel

# tcptrace network.dmp 
1 arg remaining, starting with 'network.dmp'
Ostermann's tcptrace -- version 6.6.7 -- Thu Nov  4, 2004

511677 packets seen, 511487 TCP packets traced
elapsed wallclock time: 0:00:00.510291, 1002714 pkts/sec analyzed
trace file elapsed time: 0:02:35.836372
TCP connection info:
  1: zaber:54581 - boulder:111 (a2b)                   6>    5<  (complete)
  2: zaber:833 - boulder:32774 (c2d)                   6>    5<  (complete)
  3: zaber:pcanywherestat - 172.16.39.5:53086 (e2f)    2>    3<
  4: zaber:716 - boulder:2049 (g2h)                  347>  257<
  5: 172.16.39.100:58029 - zaber:12865 (i2j)           7>    5<  (complete)
  6: 172.16.39.100:47592 - zaber:36814 (k2l)        255380> 255378<  (reset)
  7: breakpoint:45510 - zaber:7012 (m2n)               9>    5<  (complete)
  8: zaber:35813 - boulder:111 (o2p)                   6>    5<  (complete)
  9: zaber:837 - boulder:32774 (q2r)                   6>    5<  (complete)
 10: breakpoint:45511 - zaber:7012 (s2t)               9>    5<  (complete)
 11: zaber:59362 - boulder:111 (u2v)                   6>    5<  (complete)
 12: zaber:841 - boulder:32774 (w2x)                   6>    5<  (complete)
 13: breakpoint:45512 - zaber:7012 (y2z)               9>    5<  (complete)

tcptrace 功能很強大,還可以通過過濾和布林表示式來找出有問題的連線,比如,找出轉播大於100 segments 的連線:

# tcptrace -f'rexmit_segs>100' network.dmp

如果發現連線 #10 有問題,可以檢視關於這個連線的其他資訊:

# tcptrace -o10 network.dmp

下面的命令使用 tcptrace 的 slice 模式,程式自動在當前目錄建立了一個 slice.dat 檔案,這個檔案包含了每隔15秒的轉播資訊:

# tcptrace -xslice network.dmp

# cat slice.dat 
date                segs    bytes  rexsegs rexbytes      new   active
--------------- -------- -------- -------- -------- -------- --------
16:58:50.244708    85055  4513418        0        0        6        6
16:59:05.244708   110921  5882896        0        0        0        2
16:59:20.244708   126107  6697827        0        0        1        3
16:59:35.244708   151719  8043597        0        0        0        2
16:59:50.244708    37296  1980557        0        0        0        3
17:00:05.244708       67     8828        0        0        2        3
17:00:20.244708      149    22053        0        0        1        2
17:00:35.244708       30     4080        0        0        0        1
17:00:50.244708       39     5688        0        0        0        1
17:01:05.244708       67     8828        0        0        2        3
17:01:11.081080       37     4121        0        0        1        3