大容量 SSD(即 30TB 及以上)带来了一系列新的挑战。其中最相关的两个方面是:
- 大容量 SSD 采用的是高密度 NAND,比如 QLC(即四层单元 NAND,每个单元可存储 4 位数据),它与 TLC NAND(三层单元,每个单元可存储 3 位数据)相比,带来的挑战更多。
- SSD 容量的增长要求与之映射的本地 DRAM 内存容量也必须相应增长,传统上二者一直是 1:1000 的比例(DRAM 容量与存储容量之比)。
目前,我们正处于无法继续维持 1:1000 比例的时候。但,我们真的有必要维持它吗? 为什么这个比例不是 1:4000? 或者是 1:8000? 这样的话,对 DRAM 容量的需求将分别减少 4 倍或 8 倍。是什么原因阻止了我们这样做?
本文将探讨这一做法背后的思维过程,并试着为大容量 SSD 绘制一条前进的道路。
首先,为什么 DRAM 容量需要与 NAND 容量达到 1:1000 的比例? SSD 需要将来自系统的逻辑块地址 (LBA) 映射到 NAND 页,并且需要保留所有这些地址的实时副本,以便知道应该向何处写入或读回数据。LBA 大小为 4KB,映射地址一般为 32 位(4 字节),因此对于每 4KB 的 LBA,我们需要创建一个 4 字节的条目,二者之比为 1:1000。请注意,超大容量需要的比这稍微多一点,但为了简单起见,我们仍将使用这一比例,这会让我们的推论更简单,而且结果也不会有实质性的改变。
每个 LBA 一个映射条目是最有效的粒度,因为它使系统能够以尽可能低的粒度写入(即创建映射条目)。一般情况下,人们以 4KB 随机写入为基准,这通常用于测量和比较 SSD 的写入性能和耐用度。
然而,从长远来看,这可能并不可行。如果我们针对每 4 个 LBA 创建一个映射条目,会怎么样?或者 8 个、16 个、32+ 个 LBA 呢? 如果每 4 个 LBA 使用一个映射条目(即每 16KB 使用一个条目),我们或许能节省 DRAM 空间,但如果系统想要写入 4KB 会怎么样? 鉴于一个条目对应的是 16KB,SSD 将需要读取 16KB 页,修改其中需要写入的 4KB,然后再写回整个 16KB 页。这会影响性能(“读取 16KB,修改 4KB,写回 4KB”,而不是仅仅“写入 4KB”),但最重要的是,这会影响耐用度(系统写入 4KB,但 SSD 最终需要写入 16KB 到 NAND),将 SSD 的寿命缩短 4 倍。当这种情况发生在面临更大耐用度挑战的 QLC 技术上时,真的很令人担忧。对于 QLC,如果说有一样东西是不能浪费的,那必定是耐用度!
因此,通常的理由是不能改变映射粒度(或更正式的说法是间接寻址单元,简称 IU),否则将导致 SSD 寿命(耐用度)严重下降。
虽然上面说的全都没错,但系统真的会以 4KB 的粒度写入数据吗? 又会多久这样写入一次呢? 人们当然可以购买系统来以 4KB 读写模式运行 FIO,但实际上,人们不会这样使用系统。他们购买系统是为了运行应用、数据库、文件系统、对象存储等等。这之中有使用 4KB 写入的吗?
我们决定测量一下。我们选择了一系列不同的应用基准测试,从 TPC-H(数据分析)到 YCSB(云操作),让它们在各种数据库(Microsoft® SQL Server®、RocksDB、Apache Cassandra®)、各种文件系统(EXT4、XFS),甚至有时候在 Red Hat® Ceph® Storage 等整个软件定义存储解决方案上运行,然后测量了有多少 4KB 写入发出以及它们对写入放大(即额外的写入,会有损设备使用寿命)的贡献。
在深入分析细节之前,我们需要先了解,为什么当耐用度面临挑战时,写入大小至关重要。
一个 4KB 写入会导致“写入 16K 来修改 4K”,因此写入放大系数 (WAF) 为 4 倍。但如果是 8K 写入呢? 假设它们的 IU 相同,这会导致“写入 16K 来修改 8K”,所以 WAF=2。比之前好一点。如果我们写入 16K 呢? 它可能丝毫不会影响 WAF,因为它的结果是“写入 16K 来修改16KB”。所以,只有小块写入才会产生较高 WAF。
还有一种微妙的情况是,写入可能没有对齐,由此导致产生较高 WAF 的错位问题,不过随着写入大小增加,它也会迅速减小。
下图显示了这一趋势:
大块写入对 WAF 的影响最小。以 256KB 写入为例,如果对齐,它可能不会产生影响 (WAF=1x),或者如果没有对齐,它也只会产生很小的影响 (WAF=1.06x)。这比 4KB 写入带来的可怕 4 倍放大要好得多!
然后,我们需要分析所有写入 SSD 的操作,确定它们在 IU 中的对齐情况,以便计算每个写入对 WAF 的贡献。越大,越好。为此,我们给系统装上了一些装置来跟踪多个基准测试的 IO。我们获得了 20 分钟的样本(每个基准测试的样本数通常在 1 亿到 3 亿之间)。然后我们对它们进行了后处理来分析写入大小、IU 对齐情况,并添加了每个 IO 对 WAF 的贡献。
下表列出了每种写入大小的 IO 数量:
如图所示,大多数写入的大小要么为 4-8KB(不好),要么为 256KB+(好)。
如果我们应用上文的 WAF 图,假设所有这些 IO 都没有对齐,我们会得到“Worst case”(最坏情况)列中报告的结果:大多数 WAF 在 1.x 的范围内,少数在 2.x 的范围内,极少数在 3.x 的范围内。虽然这个结果比预期的 4 倍要好得多,但还不足以让它可行。
不过,一般情况下不会出现所有 IO 都错位的情况。为什么它们会错位? 为什么现代文件系统会创建出与如此小粒度错位的结构? 答案:它们不会这样。
我们针对每个基准测试测量了超过 1 亿个 IO,并对它们进行了后处理,以确定它们与 16KB IU 的对齐情况。结果在最后一列 WAF“Measured”(测量值)中。它通常小于 5%,即 WAF >=1.05x,这意味着我们可以将 IU 大小增加 400%,以 >5% 的寿命成本使用采用 QLC NAND 技术的大容量 SSD 和现有的小容量 DRAM 技术,而不是假设的 400%!这些结果相当令人惊讶。
有人可能会说:“现实中有很多 4KB 和 8KB 的小块写入,它们各自确实会给 WAF 带来 400% 或 200% 的贡献。这些单独的贡献虽然小但数量如此之多,难道总的 WAF 不应该要高得多吗?” 的确,它们很多,但它们很小,所以它们携带的有效载荷很小,就数据量而言,它们的影响被最小化了。在上表中,一次 4KB 写入和一次 256KB 写入一样,都算作一次写入,但后者携带的数据量是前者的 64 倍。
如果我们不按 IO 计数,而是根据 IO 数据量调整上表(即,考虑每个 IO 的大小和所移动的数据),我们会得到以下结果:
正如我们所看到的,更密集的 IO 的颜色分级现在偏向右侧,这意味着大块 IO 正在移动大量数据,因此对 WAF 的贡献很小。
最后要注意的一点是,并非所有 SSD 工作负载都适合这种方法。例如,最后一行表示 Ceph 存储节点的元数据部分,该节点会执行超小块 IO,导致 WAF=2.35,达到非常高的水平。大 IU 硬盘不适合单独用于元数据。但是,如果我们在 Ceph 中混合数据和元数据(NVMe SSD 的一种常见做法),那么数据的大小和数量会超过元数据的大小和数量,导致合并后的 WAF 受到的影响很小。
我们的测试表明,在实际应用和大多数常见基准测试中,改用 16K IU 是一种行之有效的方法。接下来我们要做的是说服业界停止使用 FIO 4K 读写作为 SSD 的基准,这种做法从来都是不现实的,并且就目前而言,不利于行业发展。
不同 IU 大小的影响
一个最明显的后续问题是:为什么是选择 16KB 的 IU 大小? 为什么不是 32KB 或 64KB,这有什么关系吗?
这个问题很好,但需要具体研究。我们可以把它变成一个更具体的问题:对于任何给定基准测试,不同 IU 大小的影响是什么?
由于我们已经有了不受 IU 大小影响的跟踪,接下来我们只需要在适当的模型中运行它们并查看影响。
图 4 显示了 IU 大小对 WAF 的影响:
从图表中可以看出一些结果:
- IU 大小很重要,WAF 会随 IU 增大而增大。解决方案没有好坏之分,每个人都必须根据自己的需求和目标进行不同的权衡。
- WAF 增大远没有人们担心的那么糟糕,就像我们在上面看到的许多情况一样。即使在最糟糕的 64KB IU 的情况下以及最激进的基准测试中,它也不到 2 倍,而不是令人担忧的 16 倍。
- 如前所述,元数据对于大 IU 来说是一个糟糕的选择,IU 越大,情况越糟糕。
- JESD 219A 是基准 WAF 的行业标准,它不是很好,但在 4KB IU 下可以接受,额外 3% 的 WAF 通常可以容忍,但在更大的 IU 下它会变得不寻常,在 64K IU 下几乎达到 9 倍。