2009年11月19日 | 標簽:?linux,?monitoring,?performance?| 作者:vpsee
磁盤通常是計算機最慢的子系統,也是最容易出現性能瓶頸的地方,因為磁盤離 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
2009年11月17日 | 標簽:?linux,?monitoring,?performance?| 作者:vpsee
這里的講到的 “內存” 包括物理內存和虛擬內存,虛擬內存(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 持續增加。