8.如何提高Linux下块设备IO的整体性能 前言:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议 。
IO调度发生在Linux内核的IO调度层 。这个层次是针对Linux的整体IO层次体系来说的 。
从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层,它们分别是:VFS层: 虚拟文件系统层 。由于内核要跟多种文件系统打交道,而每一种文件系统所实现的数据结构和相关方法都可能不尽相同,所以,内核抽象了这一层,专门用来适配各种文件系统,并对外提供统一操作接口 。
文件系统层: 不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可 。页缓存层: 负责真对page的缓存 。
通用块层: 由于绝大多数情况的io操作是跟块设备打交道,所以Linux在此提供了一个类似vfs层的块设备操作抽象层 。下层对接各种不同属性的块设备,对上提供统一的Block IO请求标准 。
IO调度层 :因为绝大多数的块设备都是类似磁盘这样的设备,所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列 。以便在不同的应用环境下有针对性的提高磁盘的读写效率,这里就是大名鼎鼎的Linux电梯所起作用的地方 。
针对机械硬盘的各种调度方法就是在这实现的 。块设备驱动层: 驱动层对外提供相对比较高级的设备操作接口,往往是C语言的,而下层对接设备本身的操作方法和规范 。
块设备层: 这层就是具体的物理设备了,定义了各种真对设备操作方法和规范 。有一个已经整理好的[Linux IO结构图],非常经典,一图胜千言:我们今天要研究的内容主要在IO调度这一层 。
它要解决的核心问题是,如何提高块设备IO的整体性能?这一层也主要是针对机械硬盘结构而设计的 。众所周知,机械硬盘的存储介质是磁盘,磁头在盘片上移动进行磁道寻址,行为类似播放一张唱片 。
这种结构的特点是,顺序访问时吞吐量较高,但是如果一旦对盘片有随机访问,那么大量的时间都会浪费在磁头的移动上,这时候就会导致每次IO的响应时间变长,极大的降低IO的响应速度 。磁头在盘片上寻道的操作,类似电梯调度,实际上在最开始的时期,Linux把这个算法命名为Linux电梯算法,即:如果在寻道的过程中,能把顺序路过的相关磁道的数据请求都“顺便”处理掉,那么就可以在比较小影响响应速度的前提下,提高整体IO的吞吐量 。
这就是我们为什么要设计IO调度算法的原因 。目前在内核中默认开启了三种算法/模式:noop,cfq和deadline 。
严格算应该是两种:因为第一种叫做noop,就是空操作调度算法,也就是没有任何调度操作,并不对io请求进行排序,仅仅做适当的io合并的一个fifo队列 。目前内核中默认的调度算法应该是cfq,叫做完全公平队列调度 。
这个调度算法人如其名,它试图给所有进程提供一个完全公平的IO操作环境 。注:请大家一定记住这个词语,cfq,完全公平队列调度,不然下文就没法看了 。
cfq为每个进程创建一个同步IO调度队列,并默认以时间片和请求数限定的方式分配IO资源,以此保证每个进程的IO资源占用是公平的,cfq还实现了针对进程级别的优先级调度,这个我们后面会详细解释 。查看和修改IO调度算法的方法是:cfq是通用服务器比较好的IO调度算法选择,对桌面用户也是比较好的选择 。
但是对于很多IO压力较大的场景就并不是很适应,尤其是IO压力集中在某些进程上的场景 。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度,而不是让所有的进程公平的使用IO,比如数据库应用 。