操作系统级别 IO 性能
# iostat -xm 1
Linux 3.10.0-229.el7.x86_64 (demo.example.com) 11/04/2019 _x86_64_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.44 0.00 0.48 0.31 0.00 98.76
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.19 0.47 2.38 0.61 0.08 0.01 62.85 0.09 31.47 37.77 6.71 1.83 0.55
sdb 0.00 0.00 0.00 0.00 0.00 0.00 8.06 0.00 0.08 0.08 0.00 0.08 0.00
dm-0 0.00 0.00 0.19 0.45 0.00 0.00 8.00 0.07 102.24 7.55 142.81 0.63 0.04
dm-1 0.00 0.00 2.33 0.59 0.08 0.01 62.39 0.09 32.12 38.68 6.04 1.84 0.54
在上面的例子中,有两块硬盘 sda, sdb,sda 上有两个分区 sda1(用于 /boot) 和 sda2(用作PV)。dm-0 和 dm-1 是 swap 和 / 对应的 LV。
指标 | 说明 |
%user: | CPU处在用户模式下的时间百分比 |
%nice: | CPU处在带NICE值的用户模式下的时间百分比 |
%system: | CPU处在系统模式下的时间百分比 |
%iowait: | CPU等待IO完成时间的百分比,如果该值过高,表示硬盘存在I/O瓶颈 |
%steal: | 管理程序维护另一个虚拟处理器时,虚拟CPU的无意的等待时间的百分比 |
%idle: | 闲置cpu的百分比,如果该值高,表示CPU较空闲,如果该值高但系统响应慢时,有可能是CPU等待分配内存,此时应加大内存容量 |
rrqm/s: | 每秒进行 merge 的读操作数目 |
wrqm/s: | 每秒进行 merge 的写操作数目 |
r/s: | 每秒完成的合并后的读 I/O 设备次数, r/s+w/s 就是实际的 IOPS |
w/s: | 每秒完成的合并后的写 I/O 设备次数, r/s+w/s 就是实际的 IOPS |
rsec/s: | 每秒读扇区数 |
wsec/s: | 每秒写扇区数 |
rkB/s: | 每秒读K字节数 |
wkB/s: | 每秒写K字节数 |
avgrq-sz: | 平均每次设备I/O操作的数据大小 (扇区) |
avgqu-sz: | 平均I/O队列长度,如果avgqu-sz比较大,也表示有大量io在等待(HDD可能在4左右,SSD可以达到30左右) |
await: | 平均每次设备I/O操作的等待时间 (毫秒),如果 await 远大于 svctm,说明I/O队列太长,io响应太慢,则需要进行必要优化 |
svctm: | 平均每次设备I/O操作的服务时间 (毫秒),如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间,MAN 文档中说不要相信这个值 |
%util: | 一秒中有百分之多少的时间用于 I/O 操作,即被io消耗的cpu百分比。如果 %util 接近 100%,说明产生的I/O请求太多,磁盘很繁忙。如果该值100% 不能简单的等同于磁盘的负载满了,达到了瓶颈◦ 需要综合 avgqu-sz 、 await 等其他指标进行综合判断磁盘是否达到瓶颈。例如,尽管100%了,但是 IOPS,avgqu-sz并没有用尽,则并没有达到瓶颈 |
查看 MySQL 的 IO 情况
# iotop -u mysql
这个命令能看到 MySQL 的内部各线程号及其 IO 情况,如果想知道这些线程号具体对应什么线程名,可以通过 performance_schema.threads 表来查看线程与进程的对应关系:
mysql> select name,type,thread_id,thread_os_id,processlist_id from performance_schema.threads;
其中,srv_master_thread 行就是主线程,one_connection 为前台线程,processlist_id 可以通过 show processlist 或者 select connection_id() 查看。
注意:MySQL 5.6 版本中没有 thread_os_id 这个列。我们通过 iotop 命令找到繁忙的 mysql 线程号后,并不能通过threads表知道是什么线程在忙。我们可以通过 gdb 来帮忙。
# gdb -ex "set pagination 0" -ex "thread apply all bt" --batch -p <mysqld进程号>
这样就会打印出mysqld进程的所有线程号以及各线程正在做的事情,这样,我们就可以推断出线程号对应的线程名了。