磁盤一般是計算機最慢的子系統,也是最容易出現性能瓶頸的地方,由於磁盤離 CPU 距離最遠並且 CPU 訪問磁盤要涉及到機械操做,好比轉軸、尋軌等。訪問硬盤和訪問內存之間的速度差異是以數量級來計算的,就像1天和1分鐘的差異同樣。要監測 IO 性能,有必要了解一下基本原理和 Linux 是如何處理硬盤和內存之間的 IO 的。html
上一篇 Linux 性能監測:Memory 提到了內存和硬盤之間的 IO 是以頁爲單位來進行的,在 Linux 系統上1頁的大小爲 4K。能夠用如下命令查看系統默認的頁面大小:python
$ /usr/bin/time -v date ... Page size (bytes): 4096 ...
Linux 利用虛擬內存極大的擴展了程序地址空間,使得原來物理內存不能容下的程序也能夠經過內存和硬盤之間的不斷交換(把暫時不用的內存頁交換到硬盤,把須要的內存頁從硬盤讀到內存)來贏得更多的內存,看起來就像物理內存被擴大了同樣。事實上這個過程對程序是徹底透明的,程序徹底不用理會本身哪一部分、何時被交換進內存,一切都有內核的虛擬內存管理來完成。當程序啓動的時候,Linux 內核首先檢查 CPU 的緩存和物理內存,若是數據已經在內存裏就忽略,若是數據不在內存裏就引發一個缺頁中斷(Page Fault),而後從硬盤讀取缺頁,並把缺頁緩存到物理內存裏。缺頁中斷可分爲主缺頁中斷(Major Page Fault)和次缺頁中斷(Minor Page Fault),要從磁盤讀取數據而產生的中斷是主缺頁中斷;數據已經被讀入內存並被緩存起來,從內存緩存區中而不是直接從硬盤中讀取數據而產生的中斷是次缺頁中斷。linux
上面的內存緩存區起到了預讀硬盤的做用,內核先在物理內存裏尋找缺頁,沒有的話產生次缺頁中斷從內存緩存裏找,若是尚未發現的話就從硬盤讀取。很顯然,把多餘的內存拿出來作成內存緩存區提升了訪問速度,這裏還有一個命中率的問題,運氣好的話若是每次缺頁都能從內存緩存區讀取的話將會極大提升性能。要提升命中率的一個簡單方法就是增大內存緩存區面積,緩存區越大預存的頁面就越多,命中率也會越高。下面的 time 命令能夠用來查看某程序第一次啓動的時候產生了多少主缺頁中斷和次缺頁中斷:ios
$ /usr/bin/time -v date ... Major (requiring I/O) page faults: 1 Minor (reclaiming a frame) page faults: 260 ...
從上面的內存緩存區(也叫文件緩存區 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,只讀頁(或代碼頁),那些經過主缺頁中斷從硬盤讀取的頁面,包括不能修改的靜態文件、可執行文件、庫文件等。當內核須要它們的時候把它們讀到內存中,當內存不足的時候,內核就釋放它們到空閒列表,當程序再次須要它們的時候須要經過缺頁中斷再次讀到內存。app
Dirty pages,髒頁,指那些在內存中被修改過的數據頁,好比文本文件等。這些文件由 pdflush 負責同步到硬盤,內存不足的時候由 kswapd 和 pdflush 把數據寫回硬盤並釋放內存。ide
Anonymous pages,匿名頁,那些屬於某個進程可是又和任何文件無關聯,不能被同步到硬盤上,內存不足的時候由 kswapd 負責將它們寫到交換分區並釋放內存。工具
每次磁盤 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 能夠同時很快的移動大量數據。能夠這樣來評估 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 的代價很是大。若是系統沒有物理內存可用,就會頻繁 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