基础:Linux磁盘IO的工作原理

引入

文件系统是对存储设备上的文件,进行组织管理的一种机制。而Linux在各种文件系统实现上,又抽象了一层虚拟文件系统VFS,它定义了一组,所有文件系统都支持的,数据结构和标准接口。

这样,对应用程序来说,只需要跟VFS提供的统一接口交互,而不需要关注文件系统的具体实现;对具体的文件系统来说,只需要按照VFS的标准,就可以无缝支持各种应用程序。

VFS内部又通过目录项、索引节点、逻辑块以及超级块等数据结构,来管理文件:

  • 目录项,记录了文件的名字,以及文件与其他目录项之间的目录关系
  • 索引节点,记录了文件的元数据
  • 逻辑块,是由连续磁盘扇区构成的最小读写单元,用来存储文件数据
  • 超级块,用来记录文件系统整体的状态,比如索引节点和逻辑块的使用情况。

其中,目录项是一个内存缓存;而超级块、索引节点和逻辑块,都是存储在磁盘中的持久化数据。

问题是:磁盘又是怎么工作的呢?又有哪些指标可以用来衡量它的性能呢?

其实在Linux中,磁盘实际上是作为一个块设备来管理的,也就是以块为单位读写数据,并且支持随机读写。每个块设备都会被赋予两个设备号,分别是主、次设备号。主设备号用在驱动程序中,用来区分设备类型;而次设备号则是用来给多个同类设备编号

通用块层

跟虚拟文件系统VFS类似,为了减小不同块设备的差异带来的影响,Linux通过一个统一的通用块层,来管理各种不同的块设备。

通用块层,其实是处在文件系统和磁盘驱动中间的一个块设备抽象层。它主要有两个功能:

  • 第一个功能类似VFS。向上,为文件系统和应用程序,提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序
  • 第二个功能,通用块层还会给文件系统和应用程序发来的IO请求排队,并通过重新排序、请求合并等方式,提供磁盘读写的效率

其中,对IO请求排序的功能,也就是IO调度。事实上,Linux内核支持四种IO调度算法,分别是NONE、NOOP、CFQ以及DeadLine:

  • NONE,更确切的说,并不能算IO调度算法。因为它完全不适用任何IO调度器,对文件系统和应用程序的IO其实不做任何处理,常用在虚拟机中(此时磁盘IO调度完全由物理机负责)
  • NOOP,是最简单的一种IO调度算法。它实际上是一个先入先出的队列,只做一些最基本的请求合并,常用于SSD磁盘
  • CFQ(Completely Fair Scheduler),也被称为完全公平调度器,是现在很多发行版的默认IO调度器
    • 它为每个进程维护了一个IO调度队列,并按照时间来均匀分布每个进程的IO请求
    • 类似进程CPU调度,CFQ还支持进程IO的优先级调度,所以它适用于运行大量进程的系统;像桌面环境等
  • DeadLine:
    • 分别为读、写请求创建了不同的IO队列,可以提高机械磁盘的吞吐量,并确保达到最终期限(deadline)的请求被优先处理
    • 多用于IO压力比较中的场景,比如数据库等

通用块层是Linux磁盘IO的核心。对上,它为文件系统和应用程序,提供了块设备的标准接口;向下,把各种异构的磁盘设备,抽象为统一的块设备,并会对对文件系统的IO请求进行排队、排序、请求合并等,提高了磁盘访问的效率。

IO栈

我们可以把Linux存储系统的IO栈,由上到下分为三个层次,分别是文件系统层、通用块层和设备层。这三个IO层的关系如下图(这也是Linux存储系统的IO栈全景图)

  • 文件系统层,包括虚拟文件系统和其他各种文件系统的具体实现。它为上层的应用程序,提供标准的文件访问接口;对下会通过通用块层,来存储和管理磁盘数据
  • 通用块层,包括快设备IO队列和IO调度器。
    • 它会对文件系统的IO请求进行排队,再通过重新排序和请求合并,然后才要发送给下一级的设备层
  • 设备层,包括存储设备和响应的驱动程序,负责最终物理设备的IO操作

存储系统的IO,通常是整个系统中最慢的一环。所以,Linux通过多种缓存机制来优化IO效率。

比如说,为了优化文件缓存的性能,会使用页缓存、索引节点缓存、目录项缓存等多种缓存机制,以减少对下层块设备的直接调用

同样,为了优化块设备的访问效率,会是使用缓冲区,来缓存块设备的数据。

在这里插入图片描述

问题

⼯作中经常看到使⽤多线程读写单个磁盘中不同⽂件的实现,个⼈认为这种⽅法并不能有效地提⾼性能,因为每个线程读写磁盘的位置可能差异很⼤,且每个线程的数据的空间局部性和时间局部性存在差异,导致磁盘调度优化不⾜。不知道对不对?

实际上,这是可以提高性能的。一方面,文件的读写是有操作系统缓存的。每次文件读写并不是立即对一个磁盘IO操作,在文件系统和块设备层依然可以做很多优化(比如排序、合并)。另一方面,如果是逐个来写的话,多个线程的工作就有可能被一系列的文件读写阻塞,而分开来每个线程就只需要阻塞自己所读写的文件(假设采用阻塞IO)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值