Linux Troubleshooting 超實用系列 - Disk Analysis

大卡爾 發表於 2022-05-16
Linux

筆者歷史文章: https://github.com/CarlJi/words

關於磁碟的使用,實際生產中以下問題會較為常見:

  • No space left on device - 空間不足
  • Disk utilization 100% - 磁碟I/O過載
  • Too many open files - 檔案控制程式碼過多
  • Input/output error - 讀寫錯誤

而掌握常見的分析套路會事半功倍。

Disk usage

第一時間明確磁碟容量及使用情況總是沒錯的,這時候df -h 命令就比較方便:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             48G  4.0K   48G   1% /dev
tmpfs           9.5G  8.55G  9.5G   90% /run
/dev/sda1       275G  234G   28G  90% /
/dev/sdd1       2.7T  1.6T  1.2T  57% /disk3
/dev/sdc1       3.6T  2.6T  1.1T  72% /disk1
/dev/sdb1       3.6T  4.2G  3.6T   1% /disk2

Use% 這個指標就比較清晰展示目標磁碟已經使用多少了。

注意,第三行的tmpfs檔案系統比較特殊,其資料實際是儲存在記憶體中而非磁碟。

Inode usage

有時候我們會發現明明磁碟有容量,但是程式仍然報No space left on device,這是因為什麼呢?

答案大概率是Inode耗盡了。這時候可以通過df -i 來確認,比如:

$ df -i
Filesystem        Inodes   IUsed     IFree IUse% Mounted on
udev            12370103     518  12369585    1% /dev
tmpfs           12372788     611  12372177    1% /run
/dev/sda1       18317312 1941821  16375491   11% /
/dev/sdd1      183148544   181317058 1831468  99% /disk3
/dev/sdc1      244195328  153483 244041845    1% /disk1
/dev/sdb1      244195328    7496 244187832    1% /disk2

可以看到/disk3對應的目錄其Inode已經使用99%,很快就會耗盡。Inode代表的是檔案的metadata資訊,若inode使用過多,通常意味著目錄裡小檔案太多了。

PS: 不規範的容器化姿勢比較容易出現這個問題,比如Pod一直在產生日誌,且使用的是系統盤又不定期回收。

Disk utilization high

磁碟使用率高,一般是已經知道是哪個盤了,但如果不知道,使用iostat -x 1也能較清晰的檢視到:

$ iostat -x 1
Linux 3.19.0-80-generic  	2022年05月12日 	_x86_64_	(24 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.85    0.00    3.60    4.83    0.00   85.72

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00   237.00  441.00   48.00 56448.00  1388.00   236.55     0.97    1.98    1.02   10.83   1.00  48.80
sdb               0.00    26.00    2.00  186.00     8.00 93876.00   998.77    44.51  348.13  466.00  346.86   5.32 100.00
sdc               0.00     0.00  155.00    7.00 18132.00    16.00   224.05     6.62   47.95   46.71   75.43   4.02  65.20
sdd               0.00    30.00    8.00    8.00   900.00   212.00   139.00     0.10    6.25    3.50    9.00   6.00   9.60

PS: iostat -xd <device> 1 可以只檢視某個裝置。

可以看到sdb這塊盤,其%util指標已經100%。

但要注意,%util高並不嚴格意味著磁碟已經過載了,因為現代硬碟裝置都有並行處理多個I/O請求的能力。要關注磁碟利用率,還需要關注await(再具體就是讀r_await和寫w_await指標),這個指標大致等於單個I/O所需的平均時間,所以如果它也很大,那磁碟一定是很繁忙了。

Which processes are using the specific disk?

實際場景中,面對磁碟負載高,我們通常需要做的是找到"罪魁禍首",判斷其行為是否符合預期。

粗略的可以通過 iotop -oP 直接檢視當前正在讀寫的程式。一般機器上有哪些程式,我們應該比較清楚,所以這時候可以大致判斷出來:

$ iotop -oP
Total DISK READ :     173.26 M/s | Total DISK WRITE :     177.38 M/s
Actual DISK READ:     175.77 M/s | Actual DISK WRITE:      85.50 M/s
  PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
 6929 be/4 root      168.67 M/s  168.57 M/s  0.00 % 76.51 % dd if=/dev/sda bs=4M count=100000 of=mbr.img
  379 be/3 root        0.00 B/s   15.61 K/s  0.00 %  2.01 % [jbd2/sda1-8]

當然這種方式也存在一個問題,你是看不出目標程式具體使用哪塊磁碟的。那怎麼辦呢?可以藉助lsof +D <目錄>命令,通過正在開啟的檔案控制程式碼來識別程式:

$ lsof +D /disk2
COMMAND     PID       USER   FD   TYPE DEVICE    SIZE/OFF      NODE NAME
prometheu  1705       root  mem    REG   8,17    72567556 234356807 /disk2/prometheus_dir/data/01G2J2YMJPY9HXMP5KSPW30MM1/chunks/000001
prometheu  1705       root  mem    REG   8,17    73620431 234356815 /disk2/prometheus_dir/data/01G19H692F7JN796CBQDSFVV1W/chunks/000001
prometheu  1705       root  mem    REG   8,17    73173252 234356814 /disk2/prometheus_dir/data/01G13QSNA21PYK2R6SC0BFYZYM/chunks/000001

然後通過pidstat -d 進一步分析這些程式的讀寫情況 :

$ pidstat -d
Linux 3.19.0-80-generic 	2022年05月15日 	_x86_64_(24 CPU)
16時21分37秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
16時21分59秒     0      1705     64.00     67.19      0.00  prometheus

kB_rd/skB_wr/s 這兩個指標,能基本代表程式讀寫磁碟的速度。

Too many open files

相信後端同學大多都遇到過Too may open files的錯誤,因為高併發場景下,服務會建立很多連線,這時候就會很容易遇到這個錯誤。

可以通過ls -1 /proc/<pid>/fd | wc -l命令來檢視當前程式已經開啟了多少個檔案:

$ ls -1 /proc/1705/fd | wc -l
1258

而若想檢視某程式具體的控制程式碼限制,可以通過命令cat /proc/<pid>/limits:

$ cat /proc/1705/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             386565               386565               processes
Max open files            20240                20240                files

而若要調整這個限制,可以通過ulimit命令或修改系統檔案/etc/security/limits.conf.

EIO (input/output error)

遇到這個錯誤,一般是物理磁碟壞了。可能是整個盤壞了不能讀寫,也有可能是某個block有問題。這時候通過dmesg -T檢視核心日誌,通常會有相應的error資訊。

參考資料

  1. http://linuxperf.com/?p=156
  2. http://linuxperf.com/?p=40
  3. https://man7.org/linux/man-pages/man1/pidstat.1.html
  4. https://engineering.saltside.se/linux-troubleshooting-disk-analysis-2dc40c6c49b4