計算機有三大件:CPU、內存、磁盤,這三者有一個“拖后腿”的,那就是磁盤。在生產環境,作為數據庫角色的服務器磁盤建議拿至少4塊硬盤做RAID10,這樣既保證數據讀寫速度也保證數據的安全。如果使用普通的磁盤,即使CPU再強悍,最終的服務器性能也不會太好。
在我的職業生涯中,遇到過多次因為磁盤I/O效率低而導致MySQL查詢非常慢的問題。對于一般的小網站來說,MySQL的查詢隊列(用show processlist查看)不會超過100個,甚至不會超過10個,這是因為MySQL查詢速度非常快。如果查詢隊列數量突然變大,可能是因為網站訪問量變大也可能是因為磁盤讀寫速度變慢。
本案例背景是這樣的,一臺阿里云的機器,收到告警磁盤IO達到100%,但是登錄機器后查看并沒有什么異常,也就是說磁盤飆到100%只是短暫的一會兒。既然出現了100%的情況,那說明肯定是有某個進程有問題。由于這個問題并不是一直出現,所以排查起來有點困難。于是,想到寫一個監測腳本,來實時查看磁盤IO使用情況,當發現異常時,則通過一些查看服務器狀態的指令來記錄具體的指標,從而分析出是什么造成的磁盤IO使用率100%。
知識點一:使用iostat查看磁盤IO
如果你系統中沒有iostat命令,需要安裝sysstat包,CentOS安裝方法是:
# yum install -y sysstat
iostat命令如果不加任何選項,執行結果如下:
# iostat Linux 3.10.0-862.el7.x86_64 (web30) 2022年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) 2022年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) 2022年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使用率,并找出哪個進程造成磁盤使用率很高 ##該腳本需要寫一個常駐循環 ##作者:阿銘 ##日期:2022-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使用率很高的情況,則會持續一段時間,這樣就會頻繁地記錄日志。其實,根據以前案例二中我們學過的告警收斂的思路,可以把該腳本適當修改。希望你可以動手來寫一寫,這樣才能鍛煉你的邏輯思維能力。另外,你也可以把該腳本改為發告警郵件的形式。
審核編輯:湯梓紅
-
IO
+關注
關注
0文章
448瀏覽量
39203 -
cpu
+關注
關注
68文章
10878瀏覽量
212166 -
計算機
+關注
關注
19文章
7518瀏覽量
88192 -
磁盤
+關注
關注
1文章
379瀏覽量
25224
原文標題:應用卡死可能是因為你的磁盤IO出了問題
文章出處:【微信號:aming_linux,微信公眾號:阿銘linux】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論