如何快速找出磁盤IO爲什麼那麼忙

計算機有三大件:CPU、內存、磁盤,這三者有一個“拖後腿”的,那就是磁盤。在生產環境,作爲數據庫角色的服務器磁盤建議拿至少4塊硬盤做RAID10,這樣既保證數據讀寫速度也保證數據的安全。如果使用普通的磁盤,即使CPU再強悍,最終的服務器性能也不會太好。

在我的職業生涯中,遇到過多次因爲磁盤I/O效率低而導致MySQL查詢非常慢的問題。對於一般的小網站來說,MySQL的查詢隊列(用show processlist查看)不會超過100個,甚至不會超過10個,這是因爲MySQL查詢速度非常快。如果查詢隊列數量突然變大,可能是因爲網站訪問量變大也可能是因爲磁盤讀寫速度變慢。

本案例背景是這樣的,一臺阿里雲的機器,收到告警磁盤IO達到100%,但是登錄機器後查看並沒有什麼異常,也就是說磁盤飆到100%只是短暫的一會兒。既然出現了100%的情況,那說明肯定是有某個進程有問題。由於這個問題並不是一直出現,所有排查起來有點困難。於是,想到寫一個監測腳本,來實時查看磁盤IO使用情況,當發現異常時,則通過一些查看服務器狀態的指令來記錄具體的指標,從而分析出是什麼造成的磁盤IO使用率100%。(系列學習:https://blog.51cto.com/cloumn/detail/22?from_distribution=VQcJXAFSXQExUwIAVAcGAw)

技巧一:使用iostat查看磁盤IO

如果你係統中沒有iostat命令,需要安裝sysstat包,CentOS安裝方法是:

# yum install -y sysstat

iostat命令如果不加任何選項,執行結果如下:

# iostat
Linux 3.10.0-862.el7.x86_64 (web30)     2018年11月06日     _x86_64_    (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
                 1.50      0.00     2.10         0.07      26.12     70.21

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda               15.95         1.95       108.97         545936   30453675

avg-cpu: 爲總體cpu使用情況統計信息,對於多核cpu,這裏爲所有cpu的平均值
Device: 爲各磁盤設備的IO統計信息

對於cpu統計信息一行,我們主要看iowait的值,它指示cpu用於等待io請求完成的時間。Device中各列含義如下:

Device: 爲設備名稱
tps: 爲每秒進程下發的IO讀、寫請求數量
Blk_read/s: 爲每秒讀扇區數量(一扇區爲512bytes)
Blk_wrtn/s: 爲每秒寫扇區數量
Blk_read: 爲取樣時間間隔內讀扇區總數量
Blk_wrtn: 爲取樣時間間隔內寫扇區總數量

我們經常會在iostat後面加上兩個數字,例如:

# iostat   1 3
Linux 3.10.0-862.el7.x86_64 (web30)     2018年11月06日     _x86_64_    (4 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.50    0.00    2.10    0.07   26.12   70.22

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda              15.96         1.96       109.10     546984   30511811

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.79    0.00    1.58    0.53   26.58   70.53

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda             376.00         0.00      2324.00          0       2324

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.78    0.00    1.04    0.00    9.14   89.03

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda               0.00         0.00         0.00          0          0

第一個1表示每隔1秒打印一次,3表示一共打印3次。 iostat命令還有一個非常使用的選項-x,它可以顯示更多的信息,也是我最常用的一個選項,如下:

# iostat  -d -x 1 2
Linux 3.10.0-862.el7.x86_64 (web30)     2018年11月06日     _x86_64_    (4 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     0.06    0.04   15.91     1.95   109.11    13.92     0.34   21.07    4.49   21.12   1.10   1.75

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

說明:-d選項可以把cpu相關信息過濾掉,只顯示磁盤相關信息,以下爲各列的含義:

rrqm/s: 每秒對該設備的讀請求被合併次數,文件系統會對讀取同塊(block)的請求進行合併
wrqm/s: 每秒對該設備的寫請求被合併次數
r/s: 每秒完成的讀次數
w/s: 每秒完成的寫次數
rkB/s: 每秒讀數據量(kB爲單位)
wkB/s: 每秒寫數據量(kB爲單位)
avgrq-sz:平均每次IO操作的數據量(扇區數爲單位)
avgqu-sz: 平均等待處理的IO請求隊列長度
await: 平均每次IO請求等待時間(包括等待時間和處理時間,毫秒爲單位)
svctm: 平均每次IO請求的處理時間(毫秒爲單位)
%util: 採用週期內用於IO操作的時間比率,即IO隊列非空的時間比率

對於這些列,我們最應該關注的是最後一列%util,本案例中提到磁盤使用率100%,其實就是%util的值爲100%。

技巧二:iotop查看哪個進程磁盤讀寫最高

iotop命令是一個用來監視磁盤I/O使用狀況的top類工具。iotop具有與top相似的UI,其中包括PID、用戶、I/O、進程等相關信息。iotop命令就是由iotop包安裝得來的,在CentOS下安裝iotop的方法是:

# yum install -y iotop

安裝完成後直接輸入iotop回車,結果顯示跟top類似,它是動態實時查看各個進程的磁盤讀寫情況,效果如下:

# iotop
Total DISK READ :    0.00 B/s | Total DISK WRITE :      60.42 K/s
Actual DISK READ:    0.00 B/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                                                                                       
1419 be/4 nginx       0.00 B/s    3.55 K/s  0.00 %  0.00 % nginx: worker process
9634 be/4 www         0.00 B/s   49.76 K/s  0.00 %  0.00 % php-fpm: pool www
9646 be/4 www         0.00 B/s    7.11 K/s  0.00 %  0.00 % php-fpm: pool www
  512 be/4 polkitd     0.00 B/s    0.00 B/s  0.00 %  0.00 % polkitd --no-debug
    1 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % systemd --switched-root --system --deserialize 22
    2 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kthreadd]
    3 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [ksoftirqd/0]
    5 be/0 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [kworker/0:0H]
    7 rt/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [migration/0]
    8 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_bh]
    9 be/4 root        0.00 B/s    0.00 B/s  0.00 %  0.00 % [rcu_sched]

對於各列的輸出,很容易理解,我們主要看第4和5兩列。iotop有幾個快捷鍵,如下:
左右箭頭:改變排序方式,默認是按IO排序。
r:改變排序順序。
o:只顯示有IO輸出的進程。
p:進程/線程的顯示方式的切換。
a:顯示累積使用量。
q:退出。

如果在shell腳本中使用iotop命令,需要加上-b選項,即不使用動態顯示的模式,當然還需要加另外幾個選項,具體用法如下:

# iotop -obn2
Total DISK READ :       0.00 B/s | Total DISK WRITE :       0.00 B/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO    COMMAND
Total DISK READ :       0.00 B/s | Total DISK WRITE :      59.67 K/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO    COMMAND
1416 be/4 nginx       0.00 B/s    3.51 K/s  0.00 %  0.00 % nginx: worker process
1417 be/4 nginx       0.00 B/s    3.51 K/s  0.00 %  0.00 % nginx: worker process
1418 be/4 nginx       0.00 B/s    3.51 K/s  0.00 %  0.00 % nginx: worker process
1419 be/4 nginx       0.00 B/s    3.51 K/s  0.00 %  0.00 % nginx: worker process
9638 be/4 www         0.00 B/s    3.51 K/s  0.00 %  0.00 % php-fpm: pool www

說明:-o跟上面那個快捷鍵o一個意思,它的作用是隻顯示有IO的進程。-n2表示需要統計2次,因爲第一次不會顯示任何進程。

本案例參考腳本

#!/bin/bash
##監控磁盤IO使用率,並找出哪個進程造成磁盤使用率很高
##該腳本需要寫一個常駐循環
##作者:阿銘
##日期:2018-11-06

#判斷機器上是否安裝iostat命令
if ! which iostat &>/dev/null
then
    yum install -y sysstat
    #如果你的機器爲ubuntu,請使用這個命令:apt-get install -y sysstat
fi

#判斷機器上是否安裝iotop命令
if ! which iotop &>/dev/null
then
    yum install -y iotop
    #如果你的機器爲ubuntu,請使用這個命令:apt-get install -y iotop
fi

#定義記錄日誌的目錄
logdir=/tmp/iolog
[ -d $logdir ] || mkdir $logdir

#定義日誌名字
dt=`date +%F`

#定義獲取io的函數(取5次平均值)
get_io()
{    
    iostat -dx 1 5 > $logdir/iostat.log
    sum=0

    #取最後一列的%util值循環遍歷然後相加
    for ut in  `grep "^$1" $logdir/iostat.log|awk '{print $NF}'|cut -d. -f1`
    do
        sum=$[$sum+$ut]
    done
    echo $[$sum/5]
}

#這裏的true表示條件爲真
while true
do
    #獲取所有設備,對所有設備名遍歷
    for d in `iostat -dx|egrep -v '^$|Device:|CPU\)'|awk '{print $1}'`
    do
        io=`get_io $d`
        #如果io使用率大於等於80
        if [ $io -ge 80 ]
        then
            #向日志裏記錄時間、iostat和iotop信息
            date >> $logdir/$dt   
            cat $logdir/iostat.log >>$logdir/$dt
            iotop -obn2 >>$logdir/$dt
            echo "####################" >>$logdir/$dt
        fi
    #休眠10秒,繼續以上步驟
    done
    sleep 10
done

當然,這個腳本還並不完美,因爲一旦發生磁盤IO使用率很高的情況,則會持續一段時間,這樣就會頻繁地記錄日誌。其實,根據以前案例二中我們學過的告警收斂的思路,可以把該腳本適當修改。希望你可以動手來寫一寫,這樣才能練習你的邏輯思維能力。 另外,你也可以把該腳本改爲發告警郵件的形式。

更多的知識點請瀏覽: https://blog.51cto.com/cloumn/detail/22?from_distribution=VQcJXAFSXQExUwIAVAcGAw

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章