Linux磁盘IO排查与性能优化实战

178 阅读4分钟

服务器慢,CPU和内存都正常,很可能是磁盘IO的问题。

但很多人排查到这一步就卡住了——知道是IO问题,不知道具体哪个进程、哪个文件、怎么优化。

这篇把磁盘IO排查的思路和工具整理一下。

先判断是不是IO问题

看load average

uptime
# 10:30:01 up 30 days,  1:23,  2 users,  load average: 15.32, 12.45, 8.67

load高但CPU使用率不高,大概率是IO等待。

看iowait

top

看%wa(IO Wait),如果这个值很高(比如超过20%),说明CPU在等IO。

%Cpu(s):  5.2 us,  2.1 sy,  0.0 ni, 72.3 id, 20.1 wa,  0.0 hi,  0.3 si,  0.0 st
                                              ^^^^
                                              这个

或者用vmstat:

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  5      0 234567 123456 789012    0    0   450  2300  234  567  5  2 73 20  0
    ^                                                                      ^^
    阻塞进程数                                                              wa

b列是阻塞在IO上的进程数,wa是IO等待百分比。

找出是谁在搞IO

iotop

最直观的工具,类似top但看IO:

# 需要安装
apt install iotop  # Debian/Ubuntu
yum install iotop  # CentOS

# 运行
iotop

输出:

Total DISK READ:       15.23 M/s | Total DISK WRITE:      45.67 M/s
Actual DISK READ:      15.23 M/s | Actual DISK WRITE:      32.10 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
12345 be/4  mysql       5.23 M/s   30.45 M/s  0.00 % 85.32 % mysqld
23456 be/4  root        8.00 M/s    0.00 B/s  0.00 % 45.12 % rsync

一眼就能看到是mysql和rsync在搞IO。

常用参数:

iotop -o          # 只显示有IO的进程
iotop -P          # 只显示进程,不显示线程
iotop -a          # 累计IO,而不是瞬时
iotop -p 12345    # 只看某个进程

iostat

看整体磁盘状态:

# 需要安装sysstat
iostat -xz 1
Device         r/s     w/s    rkB/s    wkB/s  rrqm/s  wrqm/s  %rrqm  %wrqm r_await w_await aqu-sz rareq-sz wareq-sz  svctm  %util
sda          25.00  150.00   400.00  3000.00    0.00   50.00   0.00  25.00    0.50   15.00   2.25    16.00    20.00   5.71  100.00
                                                                                                                           ^^^^
                                                                                                                          关键指标

关键指标:

  • %util:磁盘繁忙程度,接近100%说明磁盘很忙
  • r_await/w_await:读写平均等待时间(毫秒),越大说明越慢
  • aqu-sz:平均队列长度,越大说明请求积压越多

如果%util很高但吞吐量(rkB/s、wkB/s)不大,说明磁盘性能有问题或者是随机IO太多。

pidstat

看某个进程的IO:

pidstat -d 1
10:30:01      UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
10:30:02     1000     12345    500.00   3000.00      0.00      15  mysqld
10:30:02        0     23456   8000.00      0.00      0.00       5  rsync

指定进程:

pidstat -d -p 12345 1

找出是哪个文件

知道进程了,想知道它在读写哪个文件。

lsof

# 看进程打开的文件
lsof -p 12345

# 只看某个目录下的文件
lsof +D /var/lib/mysql/

# 看某个文件被谁打开
lsof /var/log/syslog

用strace跟踪

# 跟踪进程的IO系统调用
strace -p 12345 -e trace=read,write,open,close -f

# 统计系统调用耗时
strace -p 12345 -c

输出:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 85.23    2.345678          45     52000           write
 10.12    0.278901          12     23000           read
  3.45    0.094567           8     12000           fsync

能看到时间主要花在write和fsync上。

/proc文件系统

# 看进程的文件描述符
ls -l /proc/12345/fd/

# 看某个fd的读写位置
cat /proc/12345/fdinfo/3

常见问题和优化

问题1:日志写太多

应用疯狂写日志是常见问题。

排查:

# 找出写入最多的文件
lsof -p $(pgrep java) | grep -E "\.log$"

优化:

  • 调高日志级别(DEBUG改成INFO)
  • 异步写日志
  • 日志文件放到单独的磁盘

问题2:频繁fsync

数据库为了数据安全会频繁fsync,但很吃性能。

strace -p $(pgrep mysqld) -e fsync -c

如果fsync调用很多,考虑:

  • 调整MySQL的innodb_flush_log_at_trx_commit
  • 用SSD
  • 用带电容的RAID卡(可以安全地缓存写入)

问题3:随机IO太多

机械硬盘最怕随机IO。

判断方法:

  • iostat看r/s和w/s很高,但吞吐量不大
  • await很高

优化:

  • 换SSD(最直接)
  • 增加内存让更多数据缓存
  • 优化应用减少随机访问

问题4:swap导致IO

内存不够用了,系统把数据换到磁盘。

vmstat 1

看si和so列(swap in/out),如果不为0说明在用swap。

# 看哪个进程在用