核心内核:磁盘IO,就是内存和磁盘之间的数据读写交互。类比:书架和书桌。内存=书桌,空间小、伸手就能拿到;磁盘=书柜,容量巨大,但是起身取书慢。CPU只能直接读取内存数据;想要书柜里的资料,必须把书页搬到书桌,这个搬运动作就是磁盘IO。MySQL、Nginx、PHP性能瓶颈绝大多数场景,都是磁盘IO瓶颈。
一、本源基础术语
- 磁盘IO / I/O Input/Output
输入输出,特指内存与块设备(机械盘HDD、固态SSD)之间数据传输。CPU不直接读写磁盘,数据必须先加载到内存。 - 块设备 Block Device
磁盘、SSD,操作系统按块为最小单位读写,不是单字节。 - 块 Block
磁盘最小读写单位。Linux文件系统块常见4KB;InnoDB数据页是16KB,一次IO最少读出一整个块/页。哪怕你只需要1字节,内核也会读取整块数据到内存缓冲区。 - IO请求
应用发起一次读/写磁盘的请求。应用调用read/write系统调用,产生IO。 - IO时延 IO Latency
发起IO请求到数据读写完成的总耗时。HDD时延远高于SSD,是性能核心指标。 - IOPS Input Output Per Second
每秒能完成多少次独立IO请求。HDD IOPS很低(百级别);SSD可达数万、几十万。随机IO场景看IOPS。 - 吞吐量 Throughput
单位时间传输的数据总量,单位MB/s。顺序读写场景看吞吐量,连续拷贝大文件。
二、两种IO类型(面试重点)
- 顺序IO Sequential IO
读写的数据在磁盘上物理连续。例如连续写入redo log、大文件备份。HDD非常擅长顺序IO,吞吐量很高。 - 随机IO Random IO
每次读写的数据分散在磁盘不同位置。MySQL查询大量回表、大量零散小文件读写,都是随机IO。随机IO是HDD最大痛点,磁头需要来回寻道。
一句话区分:顺序=一页一页挨着看书;随机=不停在书柜不同格子抽书。
三、HDD机械硬盘专属术语
- 盘片、磁头、磁道、扇区
盘片:圆形磁盘薄片;磁头负责读写;磁道是同心圆轨道;扇区是硬件最小物理单元,一般512字节/4K。 - 寻道时间 Seek Time
磁头移动到目标磁道的耗时,是机械盘随机IO最主要开销。 - 旋转延迟 Rotational Latency
盘片旋转,等待目标扇区转到磁头下方的时间。 - 机械开销
寻道+旋转延迟,SSD没有这两项机械动作,所以随机IO碾压HDD。
四、操作系统IO缓存体系(Page Cache核心)
- Page Cache 页缓存
Linux内核在内存开辟的缓存,缓存磁盘块数据。读磁盘优先查Page Cache;命中就是缓存命中,无磁盘IO;不命中才触发真实磁盘读取(缺页)。写操作先写到Page Cache,不是立刻落盘。
MySQL Buffer Pool是InnoDB自己的内存缓存,Page Cache是操作系统内核缓存,两层缓存,不要混淆。
- 缺页中断 Page Fault
程序访问的数据不在内存Page Cache,内核触发中断,从磁盘加载数据页到内存。发生真实磁盘读IO。 - 脏页 Dirty Page
Page Cache里,内存中的数据已经修改,但还没有同步写入磁盘。脏页会由内核pdflush线程后台刷盘。 - 干净页 Clean Page
内存缓存的数据和磁盘文件完全一致,可直接丢弃回收内存。 - 回写 writeback
Linux默认写机制:写入Page Cache即返回成功,脏页后台异步刷入磁盘。写操作不等待磁盘物理写入。 - 直接IO Direct IO
绕过Page Cache,应用直接读写磁盘设备。MySQL可以开启,避免操作系统和引擎双层缓存冗余,消耗更多IO。
五、IO模式术语
- 阻塞IO Blocking IO
发起read调用,数据没准备好,进程挂起休眠,直到IO完成才返回。PHP-FPM默认就是阻塞IO。 - 非阻塞IO Non-blocking IO
调用read,如果数据没有就绪,系统调用立刻返回,不阻塞进程。配合IO多路复用(epoll)。注意:非阻塞只是系统调用不卡进程,磁盘IO本身依然很慢。 - 同步IO
应用发起IO,等待IO操作完成之后函数才返回。write/read阻塞等待磁盘完成。 - 异步IO AIO
发起IO请求,函数直接返回,内核完成磁盘读写之后通知应用。MySQL可以使用AIO。
易错区分:同步/异步,描述IO完成通知机制;阻塞/非阻塞,描述系统调用行为。
六、InnoDB和磁盘IO相关术语
- 数据页 Page
InnoDB最小IO单位,固定16KB。一次IO读取整个16KB页到Buffer Pool。 - 预读 Read Ahead
InnoDB预判会读取相邻数据页,提前加载到Buffer Pool。分为线性预读、随机预读,提升顺序查询性能。 - 刷脏页 Flush
Buffer Pool里修改过的数据页(脏页),后台线程刷到磁盘ibd文件。刷脏是MySQL主要写IO来源。 - redo log顺序写
redo log文件是环形日志,写入是顺序IO,性能高;脏页刷ibd是随机IO,昂贵。 - 双写缓冲区 Doublewrite Buffer
防止写页中途断电造成16KB页部分写入(页断裂)。写入ibd前,先把页写入doublewrite,属于额外IO开销。
七、监控指标术语(Linux排查IO)
- %iowait
CPU等待磁盘IO完成的时间占比。iowait高,代表CPU大量空闲,卡在等磁盘,典型IO瓶颈。
误区:iowait高一定是磁盘慢;CPU繁忙场景iowait低,不代表没有IO。
- avgqu-sz 平均IO队列长度
等待处理的IO请求队列。队列越长,IO压力越大,请求排队等待。 - await
IO请求平均等待时间(排队时间+磁盘处理时间)。核心指标,HDD await几十ms就很高,SSD一般1~5ms。 - svctm
磁盘设备本身处理IO的耗时,不含排队时间。反映磁盘硬件能力。 - util 设备使用率
磁盘设备繁忙时间占比。接近100%代表磁盘饱和,IO请求排队。 - 工具:iostat、iotop、blktrace
iostat:查看磁盘整体IO统计;iotop:看哪个进程产生大量IO;blktrace:追踪完整IO请求。
八、IO错误与限制术语
- IO hung / IO卡死
磁盘硬件故障、RAID异常,IO请求长时间无法返回,进程卡住。MySQL会hung,查询卡死。 - O_DIRECT
打开文件标记,使用Direct IO,绕过Page Cache。 - RAID 磁盘阵列
多块磁盘组合。RAID0提升性能;RAID1做镜像;RAID5兼顾容量与冗余;不同RAID的IO性能、故障容忍不一样。
九、认知误区术语
- 误区:调用write()函数,数据立刻写到磁盘
纠正:默认写Page Cache,write返回成功仅代表写入操作系统内存缓存,不是落盘。断电脏页丢失。真正持久化,需要fsync。 - 误区:Buffer Pool就是操作系统Page Cache
纠正:Page Cache属于操作系统内核;Buffer Pool是InnoDB在用户态申请的内存,两层独立缓存。 - 误区:SSD没有随机IO问题
纠正:SSD没有机械寻道延迟,随机IO远快HDD,但SSD同样存在IO队列、写放大,高压力下依然会IO瓶颈。 - 误区:iowait高 = 磁盘损坏
纠正:iowait高只是CPU在等IO,可能是大量随机读、大量刷脏页,不一定硬件损坏。 - 误区:顺序IO一定比随机IO慢
纠正:顺序IO是连续读写,HDD顺序IO性能远高于随机IO,这也是redo log设计成顺序写的底层根源。
类比串联
书桌(内存Page Cache / Buffer Pool)、书柜(磁盘)。
- 顺序IO:连续翻阅一整本书,书页挨着,取书很快;
- 随机IO:每次去书柜不同格子单独抽一页,来回跑动,非常耗时间;
- 脏页:你在书桌修改书页,还没有放回书柜;后台定时整理放回书柜就是刷脏;
- IOPS:一秒能从书柜拿出多少张纸;吞吐量:一秒搬运纸张总重量;
- await:从你开口要资料,到拿到手的总等待时间。
庖丁解牛一句话总结
磁盘IO是内存与块设备之间的数据搬运;分为顺序IO与随机IO,机械盘最大短板是随机IO;Linux有Page Cache内核缓存,InnoDB拥有独立Buffer Pool;iostat的await、%iowait、util是IO瓶颈排查指标;write写入Page Cache不等于持久化,fsync才会强制刷盘;MySQL性能问题大量根源是磁盘随机IO过高。