磁盘
机械磁盘
主要是由盘片和读写磁头组成。数据存储在盘片的的环状磁道上,读写数据前需要移动磁头,先找到对应的磁道,然后才可以访问数据。
如果数据都在同一磁道上,不需要在进行切换磁道,这就是连续IO,可以获得更好的性能。而随机IO性能就比较差。
固态磁盘
固态磁盘不需要寻找磁道,所以随机IO和连续IO性能都不错。
连续IO的性能其实比随机IO性能要好,主要连续IO可以进行预读的操作,这是其中一个性能点,另外随机IO其实还是比连续IO差。
机械磁盘的最小单位是扇区,大小是512字节
固态磁盘的最小单位是页,通常是4KB
而对于机械磁盘,因为扇区单位比较小,为了尽可能提升顺序IO,将8个扇区组成一个4KB的页。
通用块层
通用块层是处于文件系统和磁盘驱动中间的一个块设备抽象层。
- 对上层的文件系统提供统一块访问标准接口。对下层不同的磁盘设备抽象为统一的块设备。并提供统一的框架管理这些设备的驱动程序。
- 通用块层会给应用程序和文件系统发送的IO请求排队,通过重排序、请求合并等方式。提高磁盘读写效率。
IO调度算法
- NONE 什么也不做,磁盘IO调度由物理机完成。
- NOOP 是一个先入先出的队列,做一些基本的请求合并
- CFQ 完全公平调度器 为每个进程维护一个IO调度队列,并按照时间片均匀分布每个进程IO请求
- DeadLine调度算法,为读写请求创建不同的IO队列,提高机械磁盘的吞吐量。
上述其实优点一个是队列,另一个是按照进程粒度进行分配IO请求,另一个就是按照读写粒度进行处理。你看无论是编程类库,还是存储中间件都是相同的思想。
IO栈
LinuxIO栈分为 文件系统层、通用块层、设备层。
- 文件系统层,包含虚拟文件系统和其他文件系统的具体实现,为上层应用程序提供标准的文件访问接口,下层通过通用块层来存储和管理磁盘数据
- 通用块层:块设备IO队列和IO调度器,对文件系统的IO请求进行排队,在通过重新排序和请求合并。
- 设备层:存储设备和相关驱动程序,最终负责物理设备的IO操作。
存储系统的IO是最慢的地方,所以通过使用各种缓存机制来优化访问文件的性能,减少对下层块设备的直接调用。其中包含页缓存、目录项缓存、索引节点缓存。
磁盘IO观测
# -d -x表示显示所有磁盘I/O的指标
$ iostat -d -x 1
- %util ,就是我们前面提到的磁盘I/O使用率;
- r/s+ w/s ,就是 IOPS;
- rkB/s+wkB/s ,就是吞吐量;
- r_await+w_await ,就是响应时间。
进程IO观测
$ pidstat -d 1
用户ID(UID)和进程ID(PID) 。
每秒读取的数据大小(kB_rd/s) ,单位是 KB。
每秒发出的写请求数据大小(kB_wr/s) ,单位是 KB。
每秒取消的写请求数据大小(kB_ccwr/s) ,单位是 KB。
块I/O延迟(iodelay),包括等待同步块I/O和换入块I/O结束的时间,单位是时钟周期。
小结
本篇主要介绍了磁盘IO的工作原理,主要介绍了文件系统层、通用块层、设备层。而在操作系统内部其实也使用了各种的缓存来提升系统的IO读写效率。最后简要介绍来下常用的IO排查命令 iotop、pidstat -d 1 、iostat -d -x 1