1

linux IO子系统概览

 1 year ago
source link: https://www.lujun9972.win/blog/2018/04/15/linux-io%E5%AD%90%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%A7%88/index.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

linux IO子系统概览

IO子系统概况

Linux的IO子系统由VFS(Virtual File System,虚拟文件系统)层和块层构成。 其中,VFS层用于将各种不同的文件系统统一起来,形成统一的抽象层。 而块层用于通过设备驱动将数据读取或写入物理磁盘。

#+IO子系统的结构 IO_System_Struct.jpg

我们通常说的“文件系统的块大小”,指的就是块层中的设备驱动程序从物理磁盘读取/写入数据的最小单位。

值得一提的是,当分区的大小不为块大小的整数时(比如在512字节扇区的磁盘上,文件系统块大小设置为为4K,而分区不是8的整数倍时),那么最终会有一个块超出分区界限,那么这个超出分区界限的块不会在文件系统中被使用。

写入数据的情形

当写入数据时,根据上图所示,其步骤为:

  1. 当数据被写入文件系统的文件中时,首先会暂时存入磁盘高速缓存中。

    虽然这一步并未真正将数据写入物理磁盘中,但应用程序依然认为写入动作已经完成。 这些没有写入物理磁盘的数据被成为“脏数据”

  2. 当脏数据积累到一定程度,或一定时间后,文件系统会向IO调度发出请求,将脏数据写入物理磁盘中
  3. IO调度器响应请求队列中的请求,调用设备驱动程序将数据写入物理磁盘中。
  4. 设备驱动程序将数据从磁盘高速缓存写入到物理磁盘中。

读取数据的情形

当读取数据时,根据上图所示,其步骤为:

  1. 若目标数据已经存在于磁盘高速缓存中,那么文件系统直接将这些数据返回进程
  2. 若目标数据不再磁盘高速缓存中,那么进程会暂停执行进入等待状态,之后文件系统会向IO调度器发出读取数据的请求
  3. IO调度器相应请求,调用设备驱动程序把数据从物理磁盘读入磁盘高速缓存中
  4. 设备驱动程序程序把数据从物理磁盘读入磁盘高速缓存中,然后解除进程等待状态,进入就绪状态,再回到第一步

IO调度器

IO_System_Scheduler.jpg

当文件系统通过IO调度器将数据写入物理磁盘时,遵循以下步骤:

  1. 文件系统将磁盘高速缓存中的数据分配到物理磁盘的连续扇区中,每块连续的扇区都会在内核中构成一个bio对象,再把这些bio对象传递给IO调度器
  2. IO调度器接收到bio对象后将多个bio对象合并成一个请求对象,加入到请求子队列中

    bio对象的合并方法根据各IO调度器不同而不同. 一般来说,如果bio对象指定的连续扇区和已经存在的某个请求队列中的连续扇区一致,那么就会将两个对象合并,否则就创建一个只包含该bio对象的新请求对象。

  3. 子队列中的请求对象增加到一定程度后,将请求对象转移到调度队列中进行实际的写入/读取操作
  4. 设备驱动程序根据请求对象在其所指定的区域进行读取或写入。

四种IO调度器的特点

Linux主要使用以下四种IO调度器,它们的特征如下:

  1. noop(no optimization)调度器

    该调度器只有一个子队列,按照bio对象被接受时的顺序处理请求

  2. cfg(complete fair queuing)调度器

    bio对象被接收后,将发送该bio对象的进程ID通过散列函数,映射到64个子队列中的某个队列中。这样每个进程的IO请求都会被公平执行。

  3. deadline调度器

    用不同的队列来维护读请求和写请求。

    它将接收到的bio对象,根据其对应的扇区位置,以减少磁盘头移动为原则,插入到请求队列中最合适的位置。

    但是若有新的bio对象不断插入到队列前面,那么队列的请求可能一直得不到处理,因此超过一段时间没有处理的请求会被优先处理。

  4. anticipatory调度器

    在deadline调度器的基础上,会尝试预测下一个bio对象。

查看/修改调度器

查看调度器

我们可以通过 /sys/block/<磁盘名>/queue/scheduler 来查看或设置IO调度器的名称。

cat /sys/block/sda/queue/scheduler
noop deadline [cfq] 

这个意思是,本机支持的调度器有 noop, deadline, 和 cfq. 其中 sda 中采取的调度器为 cfg(被[]括起来)

此外我们也能通过 lsblk -t 命令来查看调度器

lsblk -t
NAME   ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE  RA WSAME
sda            0    512      0     512     512    0 cfq       128 128    0B
├─sda1         0    512      0     512     512    0 cfq       128 128    0B
├─sda2         0    512      0     512     512    0 cfq       128 128    0B
└─sda3         0    512      0     512     512    0 cfq       128 128    0B
sr0            0    512      0     512     512    1 cfq       128 128    0B

其中 SCHED 这一栏中现实的就是当前调度器的名称。

修改调度器

通过 echo 命令往 /sys/block/<磁盘名>/queue/scheduler 中写入新的IO调度器名称就能够临时修改当前使用的调度器。

sudo bash -c 'echo "deadline" > /sys/block/sda/queue/scheduler'
cat /sys/block/sda/queue/scheduler
noop [deadline] cfq 

可以看到,调度器被修改为 deadline 了,我们再用 lsblk 验证一下:

lsblk -t
NAME   ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED    RQ-SIZE  RA WSAME
sda            0    512      0     512     512    0 deadline     128 128    0B
├─sda1         0    512      0     512     512    0 deadline     128 128    0B
├─sda2         0    512      0     512     512    0 deadline     128 128    0B
└─sda3         0    512      0     512     512    0 deadline     128 128    0B
sr0            0    512      0     512     512    1 cfq          128 128    0B

ionice命令

通过ionice命令可以对cfq调度器中的每个进程设置优先级:

Real time这个级别进程的IO会最为优先被处理 Idle这个级别进程的IO和Real time正相反,只有在系统所有进程IO都被处理完后才会处理它 Best effort默认的优先级,给予cfq调度器的正常逻辑,公平地进行IO调度

此外,对于Real time和Best effort的进程,还能指定数值0~7的优先级参数,数值越小,优先级越高。

关于ionice的用法,可以查看帮助

ionice --help
用法:
 ionice [选项] -p <pid>...
 ionice [选项] -P <pgid>...
 ionice [选项] -u <uid>...
 ionice [选项] <命令>

设置或更改进程的 IO 调度类别和优先级。

选项:
 -c, --class <类别>    调度类别的名称或数值
                          0: 无, 1: 实时, 2: 尽力, 3: 空闲
 -n, --classdata <数字> 指定调度类别的优先级(0..7),只针对
                          “实时”和“尽力”类别
 -p, --pid <pid>...     对这些已运行的进程操作
 -P, --pgid <pgrp>...   对这些组中已运行的进程操作
 -t, --ignore           忽略失败
 -u, --uid <uid>...     对属于这些用户的已运行进程操作

 -h, --help             display this help
 -V, --version          display version

更多信息请参阅 ionice(1)。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK