本文参考 PlanetScale Blog: IO devices and latency,通过交互式动画讲解存储设备的工作原理和延迟特性。

非易失性存储是现代计算机系统的基石。每一张照片、每一封邮件、每一笔银行交易、每一份医疗记录,都保存在数字存储设备上,通常还会复制多份以确保数据持久性。

非易失性存储(俗称”磁盘”)可以在计算机断电后仍然保持数据。计算机还有其他形式的易失性存储,如CPU寄存器、CPU缓存和随机存取内存(RAM),这些存储速度更快,但需要持续供电才能工作。

在本文中,我们将通过有趣的交互式可视化元素,介绍非易失性存储设备在计算历史上的发展、功能和性能。


磁带存储 (Tape Storage)

早在1950年代,计算机就开始使用磁带驱动器进行非易失性数字存储。磁带存储系统有多种形态,从占据整个房间的大型设备,到可以放入口袋的小型驱动器(如标志性的索尼Walkman)。

磁带读取器是一个包含专门硬件的设备,用于读取磁带盒。磁带盒插入后展开,使磁带经过IO读写头,从而实现数据的读写。

虽然磁带存储数字信息已有70多年历史,但至今仍在某些应用中使用。标准LTO磁带盒有数百米长、0.5英寸宽的磁带。磁带上有多个轨道,每个轨道又分成许多小单元。单个磁带盒包含数万亿个单元。

每个单元的磁极化可以设置为向上或向下,对应二进制的0或1。磁带上的长序列位组成一个数据页面。在下面的可视化中,我们将磁带简化为简单的数据页面序列,而不是显示单个位。

🎞️ 交互式磁带读取器

你可以控制磁带速度,发起读写请求,并观察这些操作需要多长时间。在左上角可以看到待处理的IO操作队列。

▲ 读写头
1x
状态: 就绪

如果你花足够时间体验这个演示,你会注意到:

  1. 如果读/写的单元”靠近”读写头,速度很快
  2. 如果读/写的单元”远离”读写头,速度很慢

即使是现代磁带系统,读取距离较远的数据也可能需要数十秒,因为可能需要让磁带旋转数百米才能到达目标数据。

磁带场景对比

让我们通过两个具体的交互式示例进一步说明这一点。

场景1:顺序IO

假设我们需要读取4个页面,并写入另外4个页面。在这个场景中,所有4个需要读取的页面都是连续排列的,4个写入页面紧跟在读取之后。

场景1:顺序读写

R0 R1 R2 R3 W4 W5 W6 W7

如你所见,大约需要3-4秒。在真实系统中,IO头操作更快,电机驱动卷轴更快,速度会快得多。

场景2:随机IO

现在考虑另一个场景,我们需要读写相同数量的页面,但这些读写分散在整个磁带上:

场景2:随机读写

R2 W15 R8 W3 R19 W10 R5 W18

同样数量的读写操作花费了约7倍的时间!想象一下如果这个系统用来加载你的社交媒体信息流或电子邮件收件箱,可能需要数十秒甚至整整一分钟才能显示,这是完全不可接受的。

磁带的适用场景

虽然随机读写的延迟很差,但磁带系统在按顺序读写数据时表现相当好。事实上,磁带存储至今在现代科技界仍有许多应用场景。磁带特别适合需要大量存储、不需要频繁读取但需要安全保存的情况。这是因为磁带的每GB成本更低,保存寿命也比竞争对手(固态硬盘和机械硬盘)更长。

例如,CERN有一个磁带存储数据仓库,管理着超过400PB的数据。AWS也提供磁带归档服务

但磁带不适合高流量的事务性数据库。对于这些和许多其他高性能任务,需要其他存储介质。


机械硬盘 (Hard Disk Drives)

存储技术的下一个重大突破是机械硬盘。

与将数据存储在磁带上不同,HDD将数据存储在称为盘片(Platter)的小型圆形金属盘上。这个盘片放置在一个特殊的外壳内,配有读/写头,并以非常快的速度旋转(例如7200 RPM很常见)。与磁带一样,盘片也分为磁道(Track)。但是,磁道是圆形的,单个盘片通常有超过100,000个磁道。每个磁道包含数十万个页面,每个页面包含4KB左右的数据。

HDD需要读取器和盘片的机械旋转运动,才能将数据带到正确的读取位置。HDD相对磁带的一个优势是:盘片的整个表面积100%的时间都可访问,不需要像磁带那样”展开”。结合两个不同的东西可以旋转的事实,意味着数据的读写延迟大大降低。典型的随机读取可以在1-3毫秒内完成

💿 交互式机械硬盘

你可以控制盘片速度,请求硬盘读取页面或写入附近可用的页面。如果在前一个请求完成之前发起新请求,将建立一个队列。观察盘片旋转和读写臂移动到目标磁道的过程。

7200 RPM
1x
状态: 就绪 | 磁道: 0

HDD场景对比

场景1:大部分顺序IO

假设我们需要写入3个页面,然后读取3个页面。3个写入将发生在附近的可用页面,读取来自磁道1、4和3。

HDD场景1:大部分顺序

W W W R1 R4 R3

由于大多数操作是顺序的,所有任务能够快速完成。

场景2:交错随机IO

现在考虑相同的6个读写操作,但以不同的顺序交错:

HDD场景2:交错随机

R3 W R1 W R4 W

如果你有耐心等到最后,你会注意到相同总数的读写操作花费了更长的时间。大量时间花在等待盘片旋转到读写头下的正确位置。

磁盘长期以来一直支持命令队列(Command Queueing)。因此,操作系统可以发出多个并行运行的命令,磁盘控制器可以调度读写操作以优化磁盘几何结构。

延迟对比:磁带 vs HDD

下面是一个可视化对比,帮助我们看到随机磁带读取与随机磁盘读取之间的延迟差异:

📊 延迟对比:磁带 vs HDD

磁带随机读取
~1秒 (保守估计)
HDD寻道
~2毫秒

即使HDD比磁带有所改进,在某些场景下仍然”慢”,尤其是随机读写。下一个重大突破,也是当前事务性数据库最常用的存储格式,是SSD。


固态硬盘 (Solid State Drives)

固态存储(或称”闪存”存储)发明于1980年代。当时磁带和机械硬盘主导着商业和消费存储领域。由于技术限制和成本问题,直到2000年代SSD才成为消费存储的主流。

SSD相对于磁带和HDD的优势在于:它们不依赖任何机械部件来读取数据。所有数据都通过一种称为NAND闪存的特殊非易失性晶体管进行电子读取、写入和擦除。这意味着每个1或0都可以在不移动任何物理组件的情况下读取或写入,100%通过电信号完成。

SSD被组织成一个或多个Target,每个Target包含多个Block,每个Block包含多个Page。SSD在页面级别读写数据,这意味着它们一次只能读写完整的页面。

⚡ 交互式SSD

SSD 控制器
Target 0
Target 1
Target 2
Target 3
状态: 就绪

机械部件的去除大大减少了请求发出与驱动器完成请求之间的延迟。不再需要等待东西旋转。

我们在视觉效果中展示的是小例子,但单个SSD能够存储多TB的数据。例如,假设每个页面存储4096位(4KB),每个Block存储16K页面,每个Target存储16K Block,设备有8个Target。计算结果:4K × 16K × 16K × 8 = 8,796,093,022,208位,即8TB

延迟对比:HDD vs SSD

📊 延迟对比:HDD vs SSD

HDD随机读取
~2毫秒 (2000微秒)
SSD随机读取
~16微秒

SSD上的随机读取可以快至16μs(μs = 微秒,即百万分之一秒),比HDD快约100倍

人们可能会认为,去除机械部件后,SSD上的数据组织不再重要了。既然我们不必等待东西旋转,我们可以以完美的速度访问任何位置的任何数据,对吧?

不完全是。

还有其他因素影响SSD上IO操作的性能。我们不会在这里涵盖所有内容,但会讨论两个:并行性垃圾回收


SSD并行性

通常,每个Target都有一条专用线路连接到控制单元。这条线路用于处理读写操作,每条线路一次只能传输一个页面。页面可以在这些线路上非常快速地传输,但仍然需要一小段时间。数据的组织和读写序列对这些线路的使用效率有重大影响。

并行写入演示

在下面的SSD中,我们有4个Target和8个写入操作排队。点击Time IO按钮,看看当我们利用并行线路来写入这些页面时会发生什么:

SSD并行写入:分布在多个Target

控制器
W0 W1 W2 W3 W4 W5 W6 W7

在这种情况下,我们将8个页面分布在4个Target上写入。因为它们分散开了,我们能够利用并行性在两个时间片内每次写入4个页面。

串行写入演示

将其与SSD将所有8个页面写入同一个Target的序列进行比较。SSD只能使用单条数据线进行写入:

SSD串行写入:集中在单个Target

控制器
W0 W0 W0 W0 W0 W0 W0 W0

注意只有一条线路被使用,写入必须顺序进行。其他所有线路都闲置了。

这表明读写数据的顺序对性能很重要。许多软件工程师在日常工作中不需要考虑这一点,但设计MySQL等软件的人需要仔细关注数据存储的结构以及数据在磁盘上的布局。


SSD垃圾回收

SSD可以读取或写入的最小”块”是页面大小。即使你只需要其中的一部分数据,对驱动器的请求也必须以这个单位进行。

数据可以从页面读取任意次数。但是,写入有所不同。页面写入后,在旧数据被明确擦除之前,不能用新数据覆盖。棘手的是,单个页面不能被擦除。当你需要擦除数据时,必须擦除整个Block,之后其中的所有页面才能被重用。

每个SSD都需要一个内部算法来管理哪些页面是空的、哪些正在使用、哪些是脏的。脏页面是已写入但数据不再需要、准备被擦除的页面。有时数据也需要重新组织以允许新的写入流量。管理这一切的算法称为垃圾回收器(Garbage Collector)

无需垃圾回收

在下面的SSD中,所有4个Target都存储着数据。有些数据是脏的(红色文本表示)。我们想向这个SSD写入5个页面数据。

场景1:有足够的空闲页面

写入 5 个页面

第一个Target有足够的未使用页面,SSD可以愉快地将数据写入空闲页面,无需额外的垃圾回收。

需要垃圾回收

现在假设我们有一个驱动器,上面已经有不同的数据,但我们想向它写入同样的5个页面数据。在这个驱动器中,我们只有2个未使用的页面,但有很多脏页面。

场景2:需要垃圾回收

写入 5 个页面(触发GC)

为了写入5个页面数据,SSD需要花时间进行垃圾回收来腾出空间。驱动器必须将非脏页面从左上角Target移动到新位置,才能安全擦除并为新数据腾出空间。这些额外步骤显著减慢了写入性能。

这展示了驱动器上的数据组织如何影响性能。当SSD有大量读、写、删除操作时,可能会因垃圾回收而出现性能下降。虽然你可能没有意识到,忙碌的SSD会定期执行垃圾回收任务,这会减慢其他操作。

这只是SSD上数据排列影响性能的众多原因中的两个。


云存储

从磁带到磁盘再到固态硬盘的转变,使持久IO性能在过去几十年中大幅提升。然而,还有另一个现象导致了IO性能的额外变化:迁移到云端

虽然在此之前已有公司提供云计算服务,但大规模迁移到云端是在2006年Amazon AWS启动后获得了显著动力。从那时起,数万家公司将他们的应用服务器和数据库系统迁移到AWS和Google、Microsoft等公司的类似服务。

虽然这一趋势有很多优点,但也有几个缺点。其中之一是服务器往往缺乏持久性。用户在巨型数据中心内的任意硬件上租用(虚拟化的)服务器。这些服务器可能因各种原因随时关闭——硬件故障、硬件更换、网络断开等。在租用的云基础设施上构建平台时,计算机系统需要能够容忍更频繁的随时故障。

这一点,加上许多工程师对动态可扩展存储卷的渴望,导致了一个新的子现象:存储与计算分离


存储与计算分离

传统上,大多数服务器、台式机、笔记本电脑、手机和其他计算设备的非易失性存储都是直接连接的。它们通过SATA线缆、PCIe接口连接,甚至直接内置到与RAM、CPU等其他组件相同的SOC中。这对速度很有利,但带来以下挑战:

  1. 如果服务器宕机,数据也随之丢失
  2. 存储大小固定

对于应用服务器,这两点通常不是大问题,因为它们设计上就能在临时环境中良好工作。如果一个宕机了,只需启动一个新的。它们通常也不需要太多存储,因为大部分工作都在内存中进行。

数据库则完全不同。如果服务器宕机,我们不想丢失数据,而且数据大小增长很快,意味着我们可能会遇到存储限制。部分因此,许多云服务商允许你启动一个计算实例,附带一个通过网络连接的可单独配置的存储系统。换句话说,默认使用网络附加存储

当你在EC2中创建新服务器时,默认通常是连接EBS网络存储卷。许多数据库服务,包括Amazon RDS、Amazon Aurora、Google Cloud SQL和PlanetScale,都依赖于这些将计算与存储通过网络分离的存储系统。

这提供了一个很好的优势:存储卷可以随着数据的增长和缩小动态调整大小。这也意味着如果服务器宕机,数据仍然安全,可以重新连接到不同的服务器。然而,这种便利是有代价的。


本地存储 vs 网络存储

考虑以下简单配置。其中,我们有一个服务器,配有CPU、RAM和直接连接的NVMe SSD。NVMe SSD是一种使用非易失性内存主机控制器接口规范的固态硬盘,具有极快的IO速度和出色的带宽。

📊 本地存储延迟

CPU
RAM
~100ns
NVMe SSD
~50μs
CPU → RAM
~100纳秒
CPU → 本地NVMe
~50,000纳秒 (50μs)

这清楚地表明,最好尽可能将更多数据保存在内存中以获得更快的IO时间。但是,我们仍然需要磁盘,因为(A)内存更贵,(B)我们需要将数据存储在永久性介质上。虽然在这里看起来可能很慢,但本地连接的NVMe SSD是现代存储最快的选择

让我们将其与网络附加存储卷(如EBS)的速度进行比较。读写需要在数据中心内进行短暂的网络往返。往返时间明显更长,大约需要250,000纳秒(250微秒,或0.25毫秒)

📊 网络存储延迟

CPU
网络
EBS卷
~250μs
CPU → 本地NVMe
~50μs
CPU → 网络EBS
~250μs

使用同样最先进的SSD,现在完成单个读写请求需要一个数量级更长的时间。当我们有大量顺序IO时,这种负面影响可以减少,但无法消除。我们为每次访问存储系统引入了显著的延迟恶化。


IOPS限制

云端网络附加存储的另一个问题是IOPS限制。许多使用这种模型的云服务商,包括AWS和Google Cloud,会限制你可以通过网络发送的IO操作数量。

默认情况下,Amazon上的GP3 EBS实例允许你每秒发送3000 IOPS,并有一个额外的池可以累积用于偶尔的突发。

📊 IOPS突发余额演示

注意:实际的突发余额大小比这里显示的要大,为了便于演示而缩小了。

当前IOPS
0
突发余额
100%
基线: 3000 IOPS
拖动滑块调整IOPS

如果你的存储直接连接到计算实例,则没有对IO操作的人为限制。你可以以硬件允许的最快速度读写。

经过多年在IO性能上的进步,这似乎是一个倒退。这种分离带来了一些便利,但性能成本是什么?


通过复制解决数据持久性问题

我们如何克服问题1(数据持久性)和问题2(驱动器可扩展性),同时保持良好的IOPS性能?

问题1可以通过复制来克服。不是依赖单个服务器存储所有数据,我们可以将其复制到多台计算机上。一种常见的做法是让一台服务器作为主服务器,接收所有写请求。然后2台或更多额外的服务器获得所有数据的复制。数据在三个地方,丢失数据的可能性变得非常小。

📊 复制对数据丢失概率的影响

每月数据丢失概率: 1%
1%
0

让我们看看具体数字。假设在给定月份内,服务器故障的概率为1%。只有单个服务器时,我们每月有1%的概率丢失数据。这对于任何严肃的业务用途都是不可接受的。但是,有了三台服务器,这个概率下降到 1% × 1% × 1% = 0.0001%(百万分之一)

问题2可以解决,但使用直接连接SSD时需要更多手动干预。我们需要确保当磁盘接近容量限制时进行监控和警报,然后有工具可以在需要时轻松增加容量。


总结

存储类型 典型随机读取延迟 主要优势 主要劣势 适用场景
磁带 10-60秒 每GB成本最低,保存寿命最长 随机访问极慢 冷数据归档、长期备份
HDD 1-10毫秒 成本适中,容量大 机械部件限制速度 大容量存储、NAS
SSD 10-100微秒 无机械部件,速度最快 成本较高,需要垃圾回收 数据库、操作系统
本地NVMe ~50微秒 最低延迟,无IOPS限制 扩展需手动干预 高性能数据库
网络EBS ~250微秒 易扩展,故障转移简单 延迟高,IOPS受限 一般云应用

参考资料