为什么顺序写入比 HDD 上的随机写入快

why sequential write is faster than random write on HDD

就像在文件尾部附加日志条目,或者就像mysql记录它的重做日志一样,人们总是说顺序写入比随机写入快得多。但为什么?我的意思是,当您在磁盘上写入数据时,寻道时间和旋转时间决定了性能。但是在你的两个连续的顺序写入之间,可能还有很多其他的写入请求(比如 nginx 记录 access.log)。这些写入请求可能会将磁头移动到其他磁道,当您的进程进行顺序写入时,需要再次将磁头移动回来,并产生旋转时间。即使在没有其他过程的情况下,磁头可以静止不动,也需要等待旋转。 那么,顺序写入是否真的优于随机写入,仅仅是因为在许多情况下,顺序写入不包含寻道时间,而随机写入始终包含寻道时间,但顺序写入和随机写入都包含旋转时间?

磁盘的写入性能受存储设备物理属性的影响(例如机械磁盘的物理转速,单位为每分钟转数),磁盘 I/O 单位为 I/O请求大小比和OS/application.

HDD 的物理特性

传统机械磁盘的一个主要缺点是,要满足 I/O 请求,磁头必须到达所需的起始位置(寻道延迟)并且盘片必须到达所需的起始位置(旋转延迟)。

顺序和随机都是如此 I/O。然而,对于顺序 I/O,这种延迟变得相当不明显,因为可以在不重新定位磁头的情况下写入更多数据。 “高级格式”硬盘的扇区大小为 4096 字节(最小 I/O 单位),柱面大小在兆字节范围内。无需重新定位磁头即可读取整个圆柱体。因此,是的,涉及寻道和旋转延迟,但无需进一步重新定位即可 read/written 的数据量要高得多。此外,从一个柱面移动到下一个柱面比从最里面的柱面移动到最外面的柱面(最坏情况下的查找)效率要高得多。

写入 10 个连续扇区涉及一次寻道和旋转延迟,写入分布在磁盘上的 10 个扇区涉及 10 次寻道和旋转延迟。

一般来说,顺序和随机 I/O 都涉及寻道和旋转延迟。顺序 I/O 利用顺序局部性来最小化这些延迟。

SSD 的物理特性

如您所知,固态硬盘没有移动部件,因为它通常由闪存构成。数据存储在单元格中。多个单元格组成一个页面——最小的 I/O 单元,大小从 2K 到 16K 不等。多个页面以块为单位进行管理 - 一个块包含 128 到 256 个页面。

问题有两个。首先,一个页面只能被写入一次。如果所有页面都包含数据,则除非擦除整个块,否则无法再次写入它们。假设一个block中的一个page需要更新,所有page都包含数据,那么整个block都要擦除重写。

其次,单个块的写周期数是有限的。为了防止某些块比其他块更快地接近或超过最大写入周期数,使用了一种称为磨损均衡的技术,以便写入在独立于逻辑写入模式的所有块之间均匀分布。此过程还涉及块擦除。

为了减轻块擦除的性能损失,SSD 采用垃圾收集过程,通过将块页面(不包括陈旧页面)写入新块并擦除原始块来释放标记为陈旧的已用页面。

这两个方面都可能导致物理读取和写入的数据多于逻辑写入所需的数据。整页写入可以触发一个 read/write 序列,该序列大 128 到 256 倍,具体取决于 page/block 关系。这称为写入放大。随机写入可能会比顺序写入命中更多的块,从而使它们的成本明显更高。

磁盘 I/O 单位与 I/O 请求大小比率

如前所述,磁盘对可参与读取和写入的 I/O 单元施加了最小值。如果将单个字节写入磁盘,则必须读取、修改和写入整个单元。

与顺序 I/O 相比,随着 I/O 负载增加触发大量写入的可能性很高(例如,在数据库事务日志的情况下),随机 I/O往往涉及较小的 I/O 请求。随着这些请求变得小于最小 I/O 单元,处理这些请求的开销增加,增加了随机 I/O 的成本。这是由于存储设备特性而导致的写入放大的另一个示例。但是,在这种情况下,HDD 和 SSD 场景会受到影响。

OS/application

OS 有多种机制来优化顺序和随机 I/O。 由应用程序触发的写入通常不会立即处理(除非应用程序通过 synchronous/direct I/O 或同步命令请求),更改基于所谓的页面在内存中执行缓存并在稍后的时间点写入磁盘。

通过这样做,OS 最大化可用数据总量和单个 I/O 的大小。执行效率低下的单个 I/O 操作可以聚合成一个可能更大、更高效的操作(例如,对特定扇区的多个单独写入可以变成单个写入)。此策略还允许 I/O 调度,选择最有效执行 I/O 的处理顺序,即使应用程序或多个应用程序定义的原始顺序不同。

考虑以下场景:一个网络服务器请求日志和一个数据库事务日志被写入同一个磁盘。如果 web 服务器写操作按顺序执行,通常会干扰数据库写操作,如所涉及的应用程序所发出的那样。由于基于页面缓存的异步执行,OS 可以重新排序那些 I/O 请求以触发两个大的顺序写入请求。在执行这些操作时,数据库可以继续写入事务日志,不会有任何延迟。

这里需要注意的是,虽然这对于网络服务器日志来说应该是正确的,但并不是所有的写入都可以随意重新排序。每当必须将事务日志作为提交的一部分写入稳定存储时,数据库就会触发磁盘同步操作(fsync on Linux/UNIX,FlushFileBuffers on Windows)。然后,OS 不能再延迟写入操作,必须立即执行所有先前对相关文件的写入。如果 Web 服务器要执行相同的操作,则可能会对性能产生显着影响,因为顺序随后由这两个应用程序决定。这就是为什么最好将事务日志放在专用磁盘上以在存在其他磁盘同步/大量其他 I/O 操作的情况下最大化顺序 I/O 吞吐量(网络服务器日志不应该这不是问题)。否则,随着总 I/O 负载 and/or 磁盘同步数量的增加,基于页面缓存的异步写入可能无法再隐藏 I/O 延迟。