Linux磁盘I/O

188 阅读11分钟

 

Linux I/O 栈架构

应用程序

系统调用(read/write)

VFS (虚拟文件系统层)

文件系统(ext4/xfs等)

Page Cache (内核缓冲区)

Block Layer (块设备层)

I/O Scheduler (调度层)

设备驱动

物理存储设备

1.1 Linux磁盘I/O工作原理

在 Linux 系统中,磁盘主要分为机械磁盘(Hard Disk Drive,HDD)和固态磁盘(Solid State Disk,SSD),普通机械硬盘的盘片转速常见的有 5400 转 / 分钟和 7200 转 / 分钟,在读写零散小文件时,由于文件所在扇区不连续,磁头需要不断寻道,导致读写速度很慢,一般顺序读写速度在 100 - 200MB/s 左右,随机读写速度则更低,可能只有几十 KB/s 。

对于连续 I/O 和随机 I/O,不同磁盘有着不同的表现。连续 I/O 时,数据在磁盘上是连续存储的,就像图书馆里同一类书籍整齐排列在书架上。机械磁盘不需要频繁寻道,所以连续读写能力并不差,在随机 I/O 场景下,数据存储位置零散,如同图书馆里的书籍被打乱放置。机械磁盘需要不停地移动磁头来定位数据,寻道时间长,性能受到很大影响.

1.2文件系统的运作机制

文件系统是 Linux 系统中管理文件的重要部分.

索引节点(inode),可以看作是文件的 “身份证”,记录了文件的元数据,如文件大小、访问权限、修改日期、数据的位置等 。每个文件都有唯一对应的 inode,它和文件内容一样,会被持久化存储到磁盘中,所以 inode 也占用磁盘空间 。例如,当我们在 Linux 系统中查看一个文件的属性时,显示的文件大小、所有者、权限等信息就来自于 inode

目录项(dentry),则像是文件的 “名片”,记录了文件的名字、索引节点指针以及与其他目录项的关联关系 。多个关联的目录项构成了文件系统的目录结构 。它是由内核维护的一个内存数据结构,也被叫做目录项缓存 。比如我们在文件管理器中看到的文件和文件夹名称,这些都是目录项的体现,通过目录项,我们可以快速找到对应的 inode,进而访问文件 。 目录项和索引节点是多对一的关系,这意味着一个文件可以有多个别名,就像一个人可以有多个昵称,比如软链接文件,就是多了一个指向相同 inode 的目录项 。

虚拟文件系统(Virtual File System,VFS)是 Linux 内核中一个非常重要的抽象层,它就像一个万能的翻译官,为各种不同的文件系统提供了统一的接口 。由于 Linux 系统支持多种文件系统,如 EXT4、XFS、Btrfs 等,每种文件系统的实现细节都不同,如果没有 VFS,应用程序和内核就需要针对不同的文件系统编写不同的代码,这无疑会大大增加开发和维护的难度 。

​编辑

VFS,它定义了一组所有文件系统都支持的数据结构和标准接口,用户进程和内核中的其他子系统只需要跟 VFS 提供的统一接口进行交互,而不需要关心底层各种文件系统的实现细节 。例如,当我们使用 “open”“read”“write” 等系统调用操作文件时,实际上是通过 VFS 这个翻译官,将这些操作转发到底层具体的文件系统去执行 。在系统启动时,VFS 会被建立,在内存中构建起文件系统的树形结构,管理着各种文件系统的挂载点、inode 等信息,直到系统关闭时才会消亡 。

按照存储位置的不同,这些文件系统可以分为三类。

  • 第一类是基于磁盘的文件系统,也就是把数据直接存储在计算机本地挂载的磁盘中。常见的 Ext4、XFS、OverlayFS等,都是这类文件系统。
  • 第二类是基于内存的文件系统,也就是我们常说的虚拟文件系统。这类文件系统,不需要任何磁盘分配存储空间,但会占用内存。我们经常用到的 /proc就是一种最常见的虚拟文件系统。
  • 第三类是网络文件系统,也就是用来访问其他计算机数据的文件系统,比如 NFS、SMB、iSCSI 等。

1.3 I/O 操作的流程

以读取文件为例,应用程序发起读取文件的请求,这个请求首先会到达内核空间 。内核会先检查页缓存(Page Cache),页缓存就像一个高速的临时仓库,存储着最近访问过的文件片段,这些片段更有可能在近期再次被访问 。如果所需数据已经在页缓存中,那就如同在自家附近的小仓库中找到了需要的物品,直接从页缓存中将数据复制到应用程序的内存空间中,这个过程非常迅速,不需要访问慢速的磁盘 。

要是页缓存中没有找到所需数据,就会触发缺页错误(Page Fault) 。此时,内核就像一个勤劳的快递员,需要从磁盘中读取数据 。内核会通过文件系统找到数据在磁盘上的位置,向磁盘发出 I/O 请求 。磁盘接收到请求后,开始工作,机械磁盘需要移动磁头定位到数据所在的磁道和扇区,固态磁盘则通过电子信号快速读取数据 。读取到的数据会被加载到页缓存中,然后再从页缓存复制到应用程序的内存空间 。如果页缓存已满,内核会按照一定的算法,如最近最少使用(Least Recently Used,LRU)算法,将最近最少使用的页面刷新到磁盘并从缓存中驱逐,以腾出空间给新页面 。

应用read() → VFS → 检查Page Cache → 命中则返回
↓ (未命中)
文件系统 → 构造bio请求 → I/O调度器 → 设备驱动 → 硬件

DMA将数据写入内存 → 填充Page Cache → 用户空间

写入操作的流程也类似,应用程序将数据写入到内核的页缓存中,标记写入的页面为脏页(Dirty Page) 。此时数据并没有立即写入磁盘,而是在内核认为合适的时候,例如系统空闲时或者脏页数量达到一定阈值时,才会将脏页的数据真正写入磁盘,这个过程称为写回(Write Back) 。这样做的好处是可以减少磁盘 I/O 操作的次数,提高系统性能,因为磁盘的写入速度相对较慢,批量写入可以提高效率 。不过,如果系统突然崩溃,可能会导致部分已写入页缓存但未写回磁盘的数据丢失 。 

应用write() → VFS → 写入Page Cache → 立即返回
↓ (延迟写)
内核线程定期刷脏页 → 文件系统 → bio → 调度器 → 驱动 → 硬件

页缓存的存在大大提高了 I/O 操作的性能,它利用了时间局部性原理(最近访问过的页面将在近期再次被访问)和空间局部性原理(物理上相邻的元素很有可能彼此接近) 。通过预读(Read - Ahead)机制,内核会提前加载可能会被访问的数据到页缓存中,预测它们的访问并摊销一些 I/O 成本 。同时,页缓存还通过延迟写入和合并相邻读取来进一步提升 I/O 性能 。

衡量磁盘I/O性能的关键指标

1、IOPS

每秒 I/O 操作次数,是衡量磁盘性能的重要指标之一 ,主要用于评估存储设备在单位时间内能够处理的 I/O 请求数量,体现了磁盘随机读写的能力 。

例如在数据库事务处理中,数据库需要频繁地读写大量小数据块,这些数据块的存储位置通常是不连续的,属于典型的随机 I/O 操作 。以电商系统的订单处理为例,当用户下单时,系统需要将订单信息写入数据库的不同表和字段中,这些写入操作的位置是随机分布的 。

2、吞吐量:数据传输速率

吞吐量,简单来说就是单位时间内成功传输的数据量 ,它就像是数据传输的 “高速公路”,反映了磁盘在单位时间内能够传输数据的能力,是衡量磁盘性能的另一个重要指标 ,单位通常是字节每秒(B/s)、千字节每秒(KB/s)或兆字节每秒(MB/s) 。在顺序 I/O 场景中,吞吐量起着至关重要的作用 。比如在视频流服务中,服务器需要将大量的视频数据连续不断地传输给用户 。假设一个高清视频的码率为 10Mbps(约 1.25MB/s),如果磁盘的吞吐量足够高,能够快速读取视频文件并传输给用户,那么用户就能流畅地观看视频,不会出现卡顿、加载缓慢等问题 。

相反,如果磁盘吞吐量不足,视频数据传输不及时,就会导致视频播放中断,用户体验极差 。再比如在数据备份场景中,需要将大量的文件从一个存储设备复制到另一个存储设备,这个过程涉及到大量的顺序读写操作 。如果磁盘吞吐量高,就能快速完成数据备份,节省时间;否则,备份过程可能会持续很长时间,影响业务的正常运行 。

影响吞吐量的因素有很多 。磁盘的类型和接口速度是重要因素之一,SSD 的顺序读写速度比 HDD 快很多,因此在顺序 I/O 场景下,SSD 的吞吐量通常更高 。例如,SATA 接口的 SSD 顺序读取速度一般在 500 - 600MB/s 左右,而 NVMe 接口的 SSD 顺序读取速度可以达到 3000MB/s 以上 。此外,数据块大小也会对吞吐量产生影响,较大的数据块可以减少 I/O 操作的次数,从而提高吞吐量 。在网络存储环境中,网络带宽也会限制吞吐量,如果网络带宽不足,即使磁盘本身的吞吐量很高,数据传输速度也会受到限制 。

3、延迟:I/O 操作的响应时间

I/O 延迟,指的是从应用程序发出 I/O 请求开始,到接收到 I/O 操作完成的响应所经历的时间 ,它就像是快递的 “送货时长”,是衡量磁盘性能的关键指标之一,直接反映了磁盘处理 I/O 请求的速度 。I/O 延迟对应用程序的性能有着深远的影响 。在实时交易系统中,如股票交易软件,每一次交易操作都需要快速读取和写入数据 。如果 I/O 延迟过高,从用户下单到系统确认交易的时间就会变长,可能会导致交易失败或者错过最佳交易时机 。再比如在游戏场景中,游戏需要实时加载各种资源,如地图、角色模型等 。如果 I/O 延迟大,游戏画面的加载就会缓慢,出现卡顿现象,严重影响玩家的游戏体验 。

I/O 延迟产生的原因主要有以下几个方面 。磁盘的物理特性是一个重要因素,对于机械硬盘来说,寻道时间和旋转延迟是导致 I/O 延迟的主要原因 。寻道时间是指磁头移动到数据所在磁道所需的时间,旋转延迟是指盘片旋转将数据所在扇区移动到磁头下方所需的时间 。由于机械硬盘的机械运动速度有限,这两个时间加起来通常会导致较高的 I/O 延迟 。而固态硬盘虽然没有机械运动部件,但也存在闪存芯片的读写延迟以及内部控制器的处理时间 。

此外,系统的负载情况也会影响 I/O 延迟 。当系统中有大量的 I/O 请求同时发生时,磁盘需要排队处理这些请求,等待时间就会增加,从而导致 I/O 延迟上升 。文件系统的设计和实现也会对 I/O 延迟产生影响,例如文件系统的元数据管理方式、缓存机制等 。