快速定位性能瓶頸,檢查出所有資源(CPU、內存、磁盤IO等)的利用率(utilization)、飽和度(saturation)和錯誤(error)度量,即USE方法
通過分析mpstat的iowait和iostat的util%,判斷IO瓶頸
IO瓶頸往往是我們可能會忽略的地方(我們常會看top、free、netstat等等,但經常會忽略IO的負載情況),今天給大家詳細分享一下如何確認一臺服務器的IO負載是否到達了瓶頸,以及可能優化、定位的點。
mpstat中看CPU的iowait高了,難道IO就瓶頸了嗎???
先來看一臺典型的IO密集型服務器的cpu統計圖:
可以看到,CPU總使用率不高,平均1.3%,max到5.6%,雖然大部分都耗在了iowait上,但才百分之五左右,應該還沒到瓶頸吧???
錯了!這裏要特別註意:iowait≠IO負載,要看真實的IO負載情況,一般使用iostat –x 命令:
你會發現iowait雖然只有5%,但是iostat中看到util% 卻到達99%,說明磁盤就沒有閑著!!!
$ iostat –x 1
avg-cpu: %user %nice %system %iowait %steal %idle
0.04 0.00 0.04 4.99 0.00 94.92
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sda 0.00 81.00 104.00 4.00 13760.00 680.00 133.70 2.08 19.29 9.25 99.90
sda1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sda2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sda3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sda4 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sda5 0.00 81.00 104.00 4.00 13760.00 680.00 133.70 2.08 19.29 9.25 99.90
這裏重點指標是svctm和util這兩列,man一下可以看到如下解釋:
svctm
The average service time (in milliseconds) for I/O requests that were issued to the device.
%util
Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%.
svctm
可以看到,svctm指的是“平均每次設備I/O操作的服務時間 (毫秒)”,而util指的是“一秒中I/O 操作的利用率,或者說一秒中有多少時間 I/O 隊列是非空的。”
util%
我們這裏發現util已經接近100%,結合man的說明“Device saturation occurs when this value is close to 100%”可以知道其實目前這臺服務器的IO已經到達瓶頸了。
那為什麽最前面的cpu統計圖的iowait項只有5.5%左右呢?因為這個iowait(也就是top裏的wa%)指的是從整體來看,CPU等待IO的耗時占比:
wa -- iowait
Amount of time the CPU has been waiting for I/O to complete.
也就是說,CPU可能拿出一部分時間來等待IO完成(iowait),但從磁盤的角度看,磁盤的利用率已經滿了(util%),這種情況下,CPU使用率可能不高,但是系統整體QPS已經上不去了,如果加大流量,會導致單次IO耗時的繼續增加(因為IO請求都堵在隊列裏了),從而影響系統整體的處理性能。
確認了IO負載過高後,可以使用iotop工具具體查看IO負載主要是落在哪個進程上了。
那如何規避IO負載過高的問題呢?具體問題具體分析:
- 如果你的服務器用來做日誌分析,要避免多個crontab交疊執行導致多進程隨機IO(參考:隨機IO vs 順序IO),避免定期的壓縮、解壓大日誌(這種任務會造成某段時間的IO抖動)。
- 如果是前端應用服務器,要避免程序頻繁打本地日誌、或者異常日誌等。
- 如果是存儲服務(mysql、nosql),盡量將服務部署在單獨的節點上,不要和其它服務共用,甚至服務本身做讀寫分離以降低讀寫壓力;調優一些buffer參數以降低IO寫的頻率等等。另外還可以參考LevelDB這種將隨機IO變順序IO的經典方式。
通過vmstat和iostat,判斷IO瓶頸
oot@localhost ~]# vmstat -n 3 (每個3秒刷新一次)
procs-----------memory--------------------swap--- ---io---- --system---- ------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 144 186164 105252 2386848 0 0 18 166 83 2 48 21 31 0
2 0 144 189620 105252 2386848 0 0 0 177 1039 1210 34 10 56 0
0 0 144 214324 105252 2386848 0 0 0 10 1071 670 32 5 63 0
0 0 144 202212 105252 2386848 0 0 0 189 1035 558 20 3 77 0
2 0 144 158772 105252 2386848 0 0 0 203 1065 2832 70 14 15
IO
-bi:從塊設備讀入的數據總量(讀磁盤)(KB/S)
-bo:寫入到塊設備的數據總量(寫磁盤)(KB/S)
隨機磁盤讀寫的時候,這2個值越大(如超出1M),能看到CPU在IO等待的值也會越大
iostat 實現
程序代碼
iostat [ -c | -d ] [ -k ] [ -t ] [ -V ] [ -x [ device ] ] [ interval [ count ] ]
-c為匯報CPU的使用情況;
-d為匯報磁盤的使用情況;
-k表示每秒按kilobytes字節顯示數據;
-t為打印匯報的時間;
-v表示打印出版本信息和用法;
-x device指定要統計的設備名稱,默認為所有的設備;
interval指每次統計間隔的時間;
count指按照這個時間間隔統計的次數。
iostat在內核2.4和內核2.6中數據來源不太一樣,對於kernel 2.4, iostat 的數據的主要來源是 /proc/partitions;在2.6中,數據來源主要是/proc/diskstats和/sys/block/sd*/stat這兩個文件
#cat /proc/diskstats | grep sda
8 0 sda 17945521 1547188 466667211 174042714 15853874 42776252 469241932 2406054445 0 137655809 2580960422
8 1 sda1 936 1876 6 12
8 2 sda2 19489178 466659986 58655070 469240224
8 3 sda3 1270 1441 33 264
8 4 sda4 4 8 0 0
8 5 sda5 648 1442 0 0
8 6 sda6 648 1442 0 0
第1列 : 磁盤主設備號(major)
第2列 : 磁盤次設備號(minor)
第3列 : 磁盤的設備名(name)
第4列 : 讀請求總數(rio)
第5列 : 合並的讀請求總數(rmerge)
第6列 : 讀扇區總數(rsect)
第7列 : 讀數據花費的時間,單位是ms.(從__make_request到 end_that_request_last)(ruse)
第8列 : 寫請求總數(wio)
第9列 : 合並的寫請求總數(wmerge)
第10列 : 寫扇區總數(wsect)
第11列 : 寫數據花費的時間,單位是ms. (從__make_request到 end_that_request_last)(wuse)
第12列 : 現在正在進行的I/O數(running),等於I/O隊列中請求數
第13列 : 系統真正花費在I/O上的時間,除去重復等待時間(aveq)
第14列 : 系統在I/O上花費的時間(use)。
#iostat -x 1
Linux 2.6.18-53.el5PAE (localhost.localdomain) 03/27/2009
avg-cpu: %user %nice %system %iowait %steal %idle
30.72 0.00 5.00 5.72 0.00 58.56
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util
sda 0.79 21.81 9.15 8.08 237.99 239.29 27.69 1.32 76.31 4.07 7.02
sdb 0.69 19.13 3.26 2.99 153.08 176.92 52.85 0.43 68.80 5.96 3.72
sdc 3.47 89.30 10.95 7.30 213.30 772.94 54.04 1.32 72.43 4.18 7.63
每項數據的含義如下,
rrqm/s: 每秒進行 merge 的讀操作數目。即 rmerge/s
wrqm/s: 每秒進行 merge 的寫操作數目。即 wmerge/s
r/s: 每秒完成的讀 I/O 設備次數。即 rio/s
w/s: 每秒完成的寫 I/O 設備次數。即 wio/s
rsec/s: 每秒讀扇區數。即 rsect/s
wsec/s: 每秒寫扇區數。即 wsect/s
rkB/s: 每秒讀K字節數。是 rsect/s 的一半,因為每扇區大小為512字節。
wkB/s: 每秒寫K字節數。是 wsect/s 的一半。
avgrq-sz: 平均每次設備I/O操作的數據大小 (扇區)。即 (rsect+wsect)/(rio+wio)
avgqu-sz: 平均I/O隊列長度。即 aveq/1000 (因為aveq的單位為毫秒)。
await: 平均每次設備I/O操作的等待時間 (毫秒)。即 (ruse+wuse)/(rio+wio)
svctm: 平均每次設備I/O操作的服務時間 (毫秒)。即 use/(rio+wio)
%util: 一秒中有百分之多少的時間用於 I/O 操作,或者說一秒中有多少時間
I/O隊列是非空的,即use/1000 (因為use的單位為毫秒),
如果 %util 接近 100%,說明產生的I/O請求太多,I/O系統已經滿負荷,該磁盤可能存在瓶頸。
svctm 一般要小於 await (因為同時等待的請求的等待時間被重復計算了),
svctm 的大小一般和磁盤性能有關,CPU/內存的負荷也會對其有影響,請求過多
也會間接導致 svctm 的增加。
await 的大小一般取決於服務時間(svctm) 以及 I/O 隊列的長度和 I/O 請求的發出模式。如果 svctm 比較接近 await,說明 I/O 幾乎沒有等待時間;如果 await 遠大於 svctm,說明 I/O 隊列太長,應用得到的響應時間變慢,如果響應時間超過了用戶可以容許的範圍,這時可以考慮更換更快的磁盤,調整內核 elevator 算法,優化應用,或者升級 CPU。
隊列長度(avgqu-sz)也可作為衡量系統 I/O 負荷的指標,但由於 avgqu-sz 是按照單位時間的平均值,所以不能反映瞬間的 I/O 洪水。
io/s = r/s +w/s
await=(ruse+wuse)/io(每個請求的等待時間)
awaitio/s=每秒內的I/O請求總共需要等待的ms
avgqu-sz=await(r/s+w/s)/1000 (隊列長度)
以下數據其實與/proc/diskstats中除設備號與設備名外的其它數據是一一對應關系,只是統計的方法略有差別而已。
#cat /sys/block/sda/stat
17949157 1547772 466744707 174070520 15855905 42781288 469298468 2406092114 2 137680700 2581025934
快速定位性能瓶頸,檢查出所有資源(CPU、內存、磁盤IO等)的利用率(utilization)、飽和度(saturation)和錯誤(error)度量,即USE方法