计算机有三大件: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浏览量
39150 -
cpu
+关注
关注
68文章
10863浏览量
211738 -
计算机
+关注
关注
19文章
7494浏览量
87935 -
磁盘
+关注
关注
1文章
379浏览量
25207
原文标题:应用卡死可能是因为你的磁盘IO出了问题
文章出处:【微信号:aming_linux,微信公众号:阿铭linux】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论