服务器慢,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。
# 看哪个进程在用