The Life Journey of an I/O Request
这篇文章主要介绍了 SSD 的基本知识,I/O 请求从 SSD 到 CPU 的整个处理过程,以及基准测试中需要关注的数据。总的来说,一个用户态 I/O 请求从应用程序发出后,会经过 (Linux 内核) I/O 引擎,(Linux 内核) 文件系统,(Linux 内核) 块层,(Linux 内核) 驱动,总线传输协议和 SSD 主控。SPDK 是另外一套流程。在虚拟化环境中访问存储设备也有所不同。这篇文章可以带你了解整个流程大概发生了什么事情,对之后的实验内容有更好的理解。
在操作系统课程中,大家都学习过机械硬盘 HDD 的结构。借用一张 Operating System Concepts 中的图 [来源]: 机械硬盘由多片 platter 组成。每片 platter 中从内到外的同心圆称为一条 track。每个 track 被分成多份,被称为 sector。sector 是机械硬盘读写的最小单位。在盘片旋转的过程中,磁头读写数据,完成数据的持久化。HDD 向操作系统暴露的接口是一个巨大的线性数组。
SSD 的结构和 HDD 完全不同。借用一张 OSTEP 的图 [来源]。SSD 内部由许多闪存芯片组成。通常来说,这些芯片都是 NAND Flash,后文用 NAND 来称呼这些芯片。NAND 有一个特性:它只能顺序追加写。如果需要修改其中的数据,则需要将某个块完全擦除后才能重新写里面的内容。你可以阅读 OSTEP 的 Flash-based SSDs 章节来了解更多关于 SSD 的信息。 由于硬件的限制,SSD 要向操作系统提供类似 HDD 的“线性数组”接口,就需要内部的 Flash Controller 做一层逻辑地址 (LBA) 到 NAND 块的转换。这个主控就叫做 FTL。
FTL 不仅负责 LBA 到块的转换,还会回收 SSD 中的垃圾。当你在 SSD 上修改(覆写)内容时,新的内容会被追加到 NAND 之后,旧的内容并不会直接从 SSD 上擦除,这就成为了垃圾。
消费级 SSD 通常来说都会提供一些额外的空间 (over provision, aka. OP),这个额外的空间在盘容量的 7% 到 28% 之间,比如 1T 的盘实际可能有 1.07T 容量的 NAND。由于 SSD 的 NAND 只能按块擦除,FTL 在内部空间告急时会将每个块中的碎片搬移到这些 OP 空间中,而后擦除整个块,从而保证盘的正常运行。 通过这层 SSD 的硬件主控 FTL,SSD 向操作系统暴露了和 HDD 相同的接口:一个可以任意修改的巨大线性数组。
SSD 的 FTL 会维护块地址到 NAND 的映射关系。在经过一系列写操作后,这一层映射关系会有所变化。为了能公平地对比不同盘(或不同情况下盘)的性能,在进行任何测试前,我们都应该让盘达到稳态。
一些 SSD 盘提供特殊的 NVMe 指令进行盘数据的擦除和恢复。对于大部分盘来说,用 128K block size 顺序写两遍盘即可让盘达到稳定状态。
一些厂商也提供了 Evaluation Guide。比如: