只读分享解决方案文档原理方案设计📅 2026-10-14🔖 Rev 1.0⏳ 还有3日到期
🔧解决方案&应用市场分析 -> 原理方案设计 -> 电子设计&技术探讨 -> 垃圾回收与预留空间_技术探讨

垃圾回收与预留空间_技术探讨

同系列 · 原理方案设计
扫码打开本页
微信扫码

垃圾回收与预留空间(Over-Provisioning)技术探讨

从「无效页占着块却不能被擦除」出发,讲透回收开销的真正来源、预留空间如何把稳态写放大压下来,以及主机侧在这两件事上究竟能做什么 —— 一份给存储方案设计者与调试工程师的技术参考 | 编制日期 2026-10-14 | 版本号 Rev 1.0

2 个粒度
回收存在的根本原因
写入以页为单位,擦除以块为单位
1 个开销源
回收真正的成本不在擦除
而在搬迁块内的有效页
7%~28%
常见预留空间档位(量级)
以器件规格书与实测为准
1 个分母
回收与预留的共同度量
写放大 WA = NAND 写量 / 主机写量
报告总结

几乎所有用过固态存储的人都遇到过同一个现象:盘刚买来很快,用一段时间就变慢,写入延迟开始抖,寿命掉得比预期快。解释往往停留在「主控在做垃圾回收」「要留点预留空间」这种一句话层面,但这句话背后的机制其实没几个人真正拆开过:回收到底在花什么时间?预留空间到底换来了什么?为什么留得越多写放大越低?

这份文档只围绕两件事展开:垃圾回收(Garbage Collection)与预留空间(Over-Provisioning)。它们是同一枚硬币的两面——回收解决「无效页占着块却不能被擦除」的问题,预留空间决定回收时有多少回旋余地。两者有一个共同的分母:写放大。把这三者的关系讲透,前面那些现象就都能推导出来,而不是靠猜。

本文不讨论具体型号的固件实现,也不做任何厂商对比。所有比例、阈值、倍数都只给行业经验区间,正式设计一律以 datasheet 与实测为准。

结论: 垃圾回收的开销不在擦除本身,而在搬迁有效页;预留空间不是浪费容量,而是用一部分标称容量去换更低的稳态写放大与更稳的性能。 二者的定量桥梁是同一个式子:稳态下回收贡献的写放大大致正比于「1 + 有效数据占比的倒数」这一类关系,而有效数据占比又由物理容量与用户容量之比决定——预留空间越大,有效数据占比越低,块被回收时需要搬走的有效页越少,写放大越低。 主机侧能做的只有三件事且作用有限:及时发送丢弃通知、做好分区对齐与容量规划、让写入尽量顺序化。不要高估主机侧的作用,也不要低估「把容量留够」这一件事的杠杆率。

读者路径

  • 想搞懂回收为什么非做不可:第 1 章(写擦粒度不一致与无效页积累)+ 第 2 章(一次回收的完整生命周期)。
  • 想知道预留空间该留多少:第 3 章(定义与口径)+ 第 4 章(量化关系与边际收益)+ 第 9 章(代价与决策框架)。
  • 在调性能抖动 / 写延迟长尾:第 5 章(触发与调度)+ 第 10 章(诊断)+ 附录 C(排查手册)。
  • 在做固件或算法选型:第 6 章(牺牲块选择)+ 第 7 章(写放大拆解)。
  • 在做主机侧驱动或系统配置:第 8 章(主机能做什么)+ 第 11 章(可观测性)。
  • 只想要速查:第 12 章(十条结论与速查表)+ 附录 B(参数速查)。

1. 垃圾回收为什么必须存在

这一章不谈任何算法,只回答一个前置问题:为什么存储器件不能像内存一样原地改写,非要多出一个「垃圾回收」的动作。答案不在软件里,而在 NAND 的物理结构里——写入的最小单位和擦除的最小单位不是同一个东西。后面所有关于预留空间、写放大、性能抖动的讨论,都是从这一条不对称推出来的。

同一块 NAND 上的两个最小单位:写以页计,擦除以块计写(Program)· 最小单位是页页页页新页页页页主机写 4 KB 数据只影响 1 个页,其余 7 个页完全不受影响页大小典型为几 KB 到十几 KB(以规格书为准)擦除(Erase)· 最小单位是块脏脏脏脏脏脏脏脏哪怕只想改其中 1 个页也必须整块 8 个页一起擦除,无法只擦 1 个块大小典型为数百个页(以规格书为准)粒度 1 · 页读写的最小单位映射表按页建索引粒度 2 · 块擦除的最小单位一个块含几十到几百个页不对称的后果改一页要动一整块这就是回收的根源图中一个块画成 8 个页仅为示意;真实器件的页块规模随工艺代际变化,具体数值以器件 datasheet 为准。写与擦除的粒度差是 FTL 存在的物理前提,也是「越用越慢」这一现象的第一块多米诺骨牌。
图 1 · 写入单位与擦除单位不一致:写以页为粒度,擦除以块为粒度

1.1 写入单位与擦除单位不一致

NAND 闪存有三层组织粒度,它们在物理上是包含关系,在操作上却各管一摊。理解这三层,是理解后面所有内容的前提:

  • 页(Page):读与写的最小单位。主机下一次读写请求(哪怕只有几百字节),落到 NAND 上也是以「页」为单位完成的一次操作。
  • 块(Block):擦除的最小单位。一个块由几十到几百个页组成,具体数量随工艺代际变化,只能查器件手册。
  • 擦除组 / 平面(Plane / Die 层面的并行单元):多通道并行与交错操作的组织单位,决定了回收能不能并行做,第 5.5 节会展开。

关键的不对称在于:写可以按页进行,擦除却只能按块进行。这个不对称不是固件设计得不好,而是物理决定的——擦除动作是对整个块的衬底施加一次高压,把块内所有浮栅晶体管的电荷一起放掉,没有「只擦其中一部分」这种操作模式。

组织粒度是哪种操作的最小单位典型规模(量级)谁能看见它对回收的意义
页(Page)读 / 写几 KB 到十几 KB主机与 FTL 都能看见映射表的索引粒度,决定小写放大
块(Block)擦除几十到几百个页只有 FTL 能看见回收的动作对象,决定搬迁开销
擦除组 / 平面并行与交错多个块FTL 与主控调度器决定一次回收能不能并行展开
Die / 通道并发与流水多个平面主控硬件调度决定回收吞吐的上限

这张表里最值得记住的一行是第二行。块是擦除的最小单位,意味着任何一次「腾出空间」的动作,都必须以块为颗粒度进行。而主机看到的却是页——这两者之间的落差,全部由 FTL 用一层间接映射来吸收,代价就是回收。

1.2 为什么不能原地更新

既然擦除只能整块,那能不能「把要改的那一页所在的块读出来,擦掉,再把数据连同改动一起写回去」?理论上可以,实际上没人这么做,原因有四条:

  • 数据会被一起擦掉:擦除是块级的,块里其余的页在此之前必须已经搬到别处,否则数据直接丢失。也就是说「原地更新」这个动作本身就要求先把整块搬走,等于已经做了一次回收。
  • 擦除耗时是写操作的量级倍数:一次块擦除的时间通常是页编程时间的数倍到数十倍(具体倍数查手册,不同代际差异很大)。把它放在每次写请求的路径上,延迟不可接受。
  • 擦除有次数上限:每个块的 P/E 次数有限。如果每次改一个字节都要擦一次块,块的寿命会在极短时间内耗尽——这比写放大的问题严重得多。
  • 掉电窗口不可接受:读出、擦除、写回这一串动作中间断电,数据处于不可恢复状态。原地更新会让掉电保护的设计复杂到无法落地。

因此所有 NAND 方案的 FTL 都采用同一个策略:异地更新(out-of-place update)。新数据写到另一个已经擦好的页上,映射表把逻辑地址指向新页,旧页原地不动地被标记为「无效」。

异地更新的代价不是免费的

异地更新把「擦除」这个昂贵动作从写路径上挪走了,代价是制造了新的垃圾:每次主机改写一个逻辑块,NAND 上就多出一个无效页。这些无效页不能单独消失,只能等它们所在的整个块被擦除时才会消失。于是「制造垃圾」和「清理垃圾」成了两个独立的动作,后者就是垃圾回收。

换句话说:回收不是 FTL 的一个可选优化,而是异地更新这个策略必然带来的配套机制。只要采用异地更新,就一定要有回收;不存在「不用回收的 NAND FTL」。

1.3 无效页的积累

一个块里的每个页,在任意时刻都处于三种状态之一。把这三种状态分清楚,回收的全部逻辑就清楚了:

页状态含义还能被读吗还能被写吗什么时候转换
有效页(Valid)映射表当前指向它,主机读这个逻辑地址会读到这里能不能(需先擦除)被改写后转为无效
无效页(Invalid / Stale)曾存过数据,但映射表已不再指向它不能直接读不能(需先擦除)只能随整块擦除消失
空闲页(Free / Erased)已擦除,可直接写入读出来是全 1能写入后转为有效

无效页是这里最特殊的一类:它占用物理空间,却不承载任何有效数据。从主机的视角看这块容量应该还空着,从 NAND 的视角看这个位置已经被占了,谁也用不了,除非把整个块擦掉。

随着主机不断改写数据,无效页会持续增长。如果什么都不做,最终所有块都会变成「有效页 + 无效页」的混合状态,没有任何一个块处于可写状态,盘就写不动了——即使主机侧显示还剩一半容量。这个现象就是「幽灵占用」:主机看到的剩余容量和 NAND 实际能承接的写入量之间出现了偏差。

无效页的积累速度取决于负载的改写密度:

  • 纯顺序写满一次:几乎不产生无效页,块写满后一直保持全有效。
  • 随机改写热点数据:每次改写都产生一个无效页,积累速度最快。
  • 删除文件:如果没有丢弃通知,FTL 并不知道这些页已经没用了,它们仍然是「有效页」,仍然会被搬来搬去——这一点第 8.1 节会展开。

1.4 垃圾回收的定义与目标

把前面的因果链收拢,垃圾回收的定义就很直接了:

垃圾回收(Garbage Collection,GC)是这样一个动作序列——挑选一个含有无效页的块,把其中仍然有效的页搬迁到别处的空闲块,更新映射表,然后把整个块擦除,使其回到可写状态。

这个动作序列同时要达成四个目标,而它们之间是互相拉扯的:

目标要什么与谁冲突冲突时的常见取舍
回收可用块尽快把块变回可写状态,别让主机写不动与「少搬迁」冲突保证最低空闲块水位优先
控制写放大每次回收搬走的有效页越少越好与「尽快回收」冲突优先挑无效页比例最高的块
磨损均衡擦除次数要在块之间摊开与「挑最脏的块」冲突在候选集里加磨损项做折中
不影响前台回收不要在主机写路径上发生与「尽快回收」冲突后台空闲时提前回收

四个目标里,「控制写放大」是本文的主线。因为写放大同时决定了两件事:器件的寿命消耗速度,以及回收动作的频繁程度。而写放大的大小,主要由两个因素决定——回收时块内还剩多少有效页(这由负载决定),以及盘上总共有多少富余空间(这就是预留空间)。

1.5 本文主线

这份文档从头到尾只讲三件事,其余内容都是这三件事的展开或验证:

  1. 回收的开销不是擦除本身,而是搬迁有效页。擦除一次块的时间是固定的、可预测的;而搬多少页是不确定的,取决于块里还剩多少有效数据。所有关于「为什么变慢」的解释,最后都要回到「搬了多少页」这个量上。
  2. 预留空间不是浪费容量,而是把稳态写放大压下来的代价交换。多留出来的那部分物理容量降低了整盘的有效数据占比,使得任意一个块被回收时,需要搬走的有效页更少。这是一笔明确的交易:用标称容量换写放大与性能稳定性。
  3. 主机侧对这两件事都不是无能为力,但能做的事很有限。真正有效的只有三件:及时发送丢弃通知、把分区对齐与容量规划做对、让写入尽量顺序化。不要高估主机侧的作用——它无法改变块的物理粒度,也无法替代预留空间。
读本文时的两个提醒

第一,本文出现的所有数字都是量级与经验区间,包括预留比例、写放大倍数、水位阈值、搬迁量。它们用来建立直觉和做量级判断,不能当作任何一颗料的规格,正式设计一律以 datasheet 与实测为准。

第二,本文的模型是单颗粒、单控制器的理想模型。多通道并行、多芯片交错、带独立协处理器的主控会带来额外的调度维度,但不改变定义与因果链——只是把「一个块」换成「一组块」,把「一次擦除」换成「一批擦除」。公式依然适用,输入参数要按实际组织粒度重新取值。

无效页从产生到积累:三次异地更新之后,块再也写不进新数据① 初始:块刚擦除空闲空闲空闲空闲空闲空闲空闲空闲8 个页全空闲可写容量 = 8 页② 写入 4 页数据有效有效有效有效空闲空闲空闲空闲4 个有效页还剩 4 页可写③ 改写前 2 页(异地更新)无效无效有效有效空闲空闲空闲空闲新增 2 个有效页在别处本块多出 2 个无效页④ 继续改写,块被填满无效无效无效无效无效无效有效有效有效 2,无效 6一个页都写不进去了触发回收关键点:主机侧看到的「已用容量」是 4 页,NAND 侧被占住的却是 8 页。多出来的 4 页就是无效页——它们不承载数据,却占了块的位置,只能靠整块擦除释放。无效页只能整块释放没有「只擦一个页」的操作改写越随机,积累越快顺序写几乎不产生无效页填满之后必须回收否则主机写入直接卡住
图 2 · 无效页的积累过程:从全空闲到写不进去,只用了三次改写

图 2 把这个积累过程画成了一个四步的示意。注意第 ④ 步:主机侧认为只用了 4 页,NAND 侧却被占住了 8 页。差的这 4 页就是无效页。当所有块都进入这种状态时,即使主机侧看到的剩余容量还很充裕,盘也写不动了——这就是为什么「容量用满」和「性能塌方」往往同时出现,第 10 章会专门讲这个现象。

2. 垃圾回收的基本流程

这一章把一次完整的回收动作拆成五个步骤讲清楚:什么时候触发、挑哪个块、搬哪些页、什么时候擦、擦完要更新什么。这五步里的每一步都有可选项,不同的固件实现在这五步上的取舍不同,表现出来的性能与寿命特征也不同。理解了这五步,第 5 章的调度策略与第 6 章的选择算法就只是这五步的具体参数化。

2.1 触发条件:空闲块水位

回收不是定时做的,也不是每次写入都做,而是由空闲块的数量触发。FTL 维护一个「已擦除、可直接写入」的块池,当池子里的块数低于某个阈值时,就开始回收。

为什么用「空闲块数」而不是「空闲页数」做判据?因为写入的原子性要求是块级的:一次写入需要一个完整的空闲页,而回收需要一个完整的空闲块来承接搬迁。用页数做水位会在「页数够、块数不够」的情况下误判——页分散在很多块里,但没有一个块是完整空闲的,此时既写不进新数据也做不了回收。

水分区间(经验)盘的状态该做什么不做会怎样
充足(高于高水位)回收毫无压力,写入走最短路径后台可以完全不回收,省电无(这是理想状态)
中等(高、低水位之间)有余量但不多后台低速回收,维持水位持续下降会进入下一档
偏低(接近低水位)空闲块不多,前台写入开始被拖后台提高回收强度前台写入开始等待回收完成
告急(低于低水位)几乎没有空闲块前台回收,写入与回收串行写延迟显著上升,出现卡顿
枯竭(无空闲块)完全写不动必须先回收才能继续写写入阻塞,表现为掉速或超时

阈值本身是个经验值,不同固件差得很多,常见做法是设成「总块数的百分之几」这个量级,并且高、低两个水位之间留出滞回区间,避免在阈值附近反复启停。具体数值没有通用答案,只能实测调整——第 5.2 节会讲怎么定。

2.2 选择牺牲块

触发之后第一步是挑一个被回收的块,行业里一般叫牺牲块(victim block)。最朴素的想法是「挑无效页最多的那个」,因为它需要搬走的有效页最少,写放大最低。这个想法在多数情况下是对的,但它有两个盲区:

  • 不考虑磨损:某个块可能一直是「最脏」的那个,反复被挑中,擦除次数远超其他块,寿命提前耗尽。
  • 不考虑数据冷热:如果块里剩下的有效页是冷数据,搬走之后它大概率不会再被改写,这是好事;如果搬的是热数据,搬完马上又变脏,等于白搬一次。

这两个盲区分别对应第 6.4 节的磨损均衡协同和第 6.3 节的冷热分离。在基本流程这一章,先把选择动作本身的输入输出讲清楚:

选择动作的要素输入输出常见实现
候选集所有含无效页的块一个待评估的子集全扫描或按脏度分桶
评估函数无效页数、擦除计数、数据年龄每块的收益/成本比贪心或成本-收益,见第 6 章
决策各块的评估值一个牺牲块取最大收益者,或加权折中
边界处理有没有全无效的块直接擦除、跳过搬迁零搬迁回收,最快的一种

2.3 搬迁有效页

这是整个回收过程中开销最大的一步,也是本文反复强调的那句话的来源:回收的成本不在擦除,而在搬迁。

搬迁的动作本身很简单:把牺牲块里每一个仍然有效的页读出来,写进目标空闲块,再把映射表里的对应项指向新位置。设一个块有 N 个页,其中有效页有 V 个,无效页有 I 个(N = V + I),那么这一次回收:

  • 产生 V 次读操作:把有效页读进内部缓冲。
  • 产生 V 次写操作:把读出来的数据写进新块。
  • 产生 1 次擦除操作:把旧块擦掉。
  • 净收益:(N - V) 个页的可用空间:也就是被释放出来的无效页数量。

用「净收益」去除「付出的写入量」,就得到这一次回收的写放大贡献:

本次回收的写放大贡献 = 搬迁写入量 / 回收出的可用空间
                    = V / (N - V)
                    = 1 / (N/V - 1)

这个式子的含义非常直白:V 越接近 N(块里几乎全是有效页),分母越小,写放大越大,趋近无穷;V 越接近 0(块里几乎全是无效页),写放大趋近 0。举两个极端情况感受一下量级:

块内有效页占比 V/N回收 1 个块腾出的空间需要搬走的页数本次回收的写放大贡献工程评价
0.1(很脏)0.9 个块0.1 个块约 0.11几乎白赚,回收效率极高
0.30.7 个块0.3 个块约 0.43很划算
0.50.5 个块0.5 个块1.00搬多少就腾出多少,打平
0.70.3 个块0.7 个块约 2.33明显不划算
0.9(很干净)0.1 个块0.9 个块9.00灾难,几乎是在做无用功
这张表就是预留空间的全部意义

把表格从上往下看,会得到一个反直觉但极其重要的结论:回收效率完全取决于「块里还剩多少有效数据」,而不是「回收算法有多聪明」。而块里剩多少有效数据,又取决于整盘的平均有效数据占比——盘子越满,每个块的有效页占比就越高,回收就越不划算。

预留空间的全部作用,就是把整盘的平均有效数据占比压低,让块在被挑中回收时,恰好处于表格上半部分那种「很脏」的状态。这不是算法技巧,这是纯粹的容量换效率。理解了这一点,第 4 章的量化关系就是这张表的直接推论。

2.4 擦除与回收

搬迁完成后,牺牲块里所有的有效数据都已经在别处有了副本,此时可以安全地执行擦除。擦除完成,块回到空闲池,本次回收结束。

擦除这一步的特点是时间长、不可打断、期间块不可访问:

子步骤耗时量级(相对)能否被打断对前台的影响备注
读有效页与页读取同量级能(可分次读)占用读带宽搬迁的读方向
写有效页到新块与页编程同量级能(可分次写)占用写带宽与空闲块搬迁的写方向
更新映射表极短(内存操作)能几乎无但必须原子地持久化
擦除块数倍到数十倍于页编程不能块在此期间不可访问是延迟尖峰的来源之一
块状态回收入池极短能无擦除完成后的记账

注意一个容易被忽略的细节:擦除期间该块不可访问。如果此时主机恰好要读这个块里的某个页(搬迁完成前的瞬间),请求会被挂起直到搬迁完成。这就是写入延迟出现长尾的一个来源——第 10.2 节会从诊断角度再讲一遍。

另外,擦除是有次数上限的。每回收一次,牺牲块的 P/E 计数加一。回收越频繁,寿命消耗越快,这就是为什么「写放大」既是性能指标也是寿命指标——它同时出现在两个预算表里。

2.5 元数据更新

搬迁与擦除之后,有一批元数据必须同步更新,否则数据就找不到了。这一步耗时极短,但正确性要求最高——它是掉电保护的核心关注点。

元数据类型更新时机必须持久化的原因写不下去会怎样
逻辑到物理映射表每搬一个页更新一项否则读回来的数据是旧的数据错乱
块状态表擦除完成后否则空闲块池可能给出未擦除的块写入失败或数据损坏
块擦除计数每次擦除后磨损均衡依赖它磨损失衡,寿命提前耗尽
有效页计数每次搬迁后牺牲块选择依赖它选错块,写放大恶化
坏块表擦除失败时否则反复使用一个坏块数据丢失风险

元数据本身也要写在 NAND 上(掉电不能丢),而写元数据本身又会产生少量额外的写入——这一项通常很小,但在写放大的精细拆解里仍然占一格,见第 7.1 节。

2.6 一次回收的完整生命周期

把上面五步串起来,一次完整的回收就是这样一条时间线。理解这条时间线,后面讨论「前台回收还是后台回收」「要不要限速」才有共同语言。

一次回收的六个阶段:只有第 3 阶段是「有效功」,其余都是配套开销1触发空闲块低于低水位后台线程或前台路径发起2选择算收益,挑牺牲块扫候选集,取最优3搬迁读有效页,写进新块这一步最花时间4改表更新映射与计数必须原子持久化5擦除整块擦除,块不可用不可打断的延迟尖峰6回池块回到空闲池,水位回升本次回收结束各阶段的开销权重(示意,随负载与实现变化,仅表量级关系)选择 8%搬迁 74%擦除 10%搬迁阶段吃掉绝大部分时间,因为它要读 V 个页、写 V 个页,而 V 是被回收块里剩下的有效页数。擦除只占很小一块——它慢,但只有一次;搬迁是很多次读写累加起来的。所以降低回收开销的正确方向是「减少 V」,而不是「想办法让擦除更快」。V 是唯一的主变量块内有效页数决定一切降低 V 的两条路留够预留空间 / 冷热分离擦除次数 = 回收次数每回收一次,寿命少一次阶段划分与开销权重为示意性拆解,不同固件实现的阶段边界与耗时比例会有差异,以实测为准。
图 3 · 一次回收的完整生命周期:触发、选择、搬迁、改表、擦除、回池

把这条时间线用一句话概括:回收的全部工作,就是在为「腾出一个块」这个目标付出 V 次读 + V 次写 + 1 次擦除的代价,而收益只有 (N - V) 个页的空间。当 V 很大的时候,这笔交易极其不划算;而当盘上有充足的预留空间时,块往往在变得「很脏」之前就被回收了,V 自然就小。

阶段主要动作是否占用前台带宽失败时的后果可以优化的方向
① 触发检查空闲块水位否不触发就没有回收提前后台触发,见第 5 章
② 选择评估候选块否(读元数据)选到坏块,白做一次更好的评估函数,见第 6 章
③ 搬迁读旧页 + 写新页是(读写都占)数据丢失风险降低 V:预留空间、冷热分离
④ 改表持久化映射与计数轻微映射错乱批量提交、日志化
⑤ 擦除整块擦除是(块不可用)块变坏块挑质量好的块,避开高温窗口
⑥ 回池记账并归还否空闲池泄漏无,纯记账
第 2 章要点小结

回收的五个步骤里,只有「搬迁」这一步的开销是可变的,其余都是固定开销。而搬迁量 V 又完全由「块里还剩多少有效数据」决定。所以所有降低回收开销的手段,归根结底都是在降低 V —— 或者让平均而言 V 更小。预留空间就是在整盘层面降低 V 的那个手段。

3. 什么是预留空间

这一章给「预留空间」下一个可计算的严格定义,并把它和几个容易混淆的概念分开:备用区、坏块替换池、厂商隐藏容量。定义清楚之后,第 4 章才谈得上量化——因为「预留 7%」这句话在不同口径下指的是两个不同的数,差了将近四分之一。

3.1 定义与口径

预留空间(Over-Provisioning,OP)最常被使用的定义是:

OP = (C_raw - C_user) / C_user

其中:
  C_raw  = NAND 上真实存在的可擦除容量(物理容量 / 裸容量)
  C_user = 主机可以访问到的容量(用户容量 / 标称容量)

这个式子的分母是用户容量,不是物理容量。这一点必须记住,因为另一种口径同样常见:

口径定义式同一盘上的数值谁在用换算关系
口径一(本文默认)OP = (C_raw - C_user) / C_user偏大(例:28%)企业级规格、性能讨论OP = OP_raw / (1 - OP_raw)
口径二OP_raw = (C_raw - C_user) / C_raw偏小(例:22%)部分厂商材料、容量说明OP_raw = OP / (1 + OP)
口径不对齐是最常见的沟通事故

「这盘预留了 28%」和「这盘预留了 22%」说的可能是同一颗盘。评审会上如果不先对齐分母,后面的写放大估算、寿命预算会全部错位。

本文统一使用口径一(除以用户容量)。如果你手上的材料用的是口径二,先按上面的式子换算过来再代入本文的公式。

3.2 物理容量与用户容量的差

物理容量和用户容量为什么会不相等?因为中间有好几层扣减。把这些扣减逐层列出来,才知道「预留空间」到底是哪一层:

层次从物理容量里扣掉了什么主机能看见吗算不算预留空间备注
第一层出厂坏块与替换块池看不见不算属于可靠性冗余,不是 OP
第二层固件代码区、映射表区、日志区看不见不算属于固件开销,是必需品
第三层ECC 校验与元数据附加区看不见不算每个页都要带,随页大小走
第四层厂商设定的固定预留(保底 OP)看不见算出厂就划定,用户改不了
第五层主机未分配的空闲空间看得见(显示为可用空间)算(等效)不写满就等于临时预留

这里有一个非常实用、也非常容易被忽略的结论:「没写满」在物理上等价于「预留了空间」。一块 100 GB 的盘,如果主机只往里写了 60 GB,剩下 40 GB 从未被写过,那些块处于已擦除状态,FTL 可以拿它们当空闲块用——效果和出厂预留 40 GB 是一样的。

反过来说:一旦盘被写满过一次,这层等效预留就永久消失了。所有块都含过数据,之后再怎么删文件(如果没有丢弃通知),FTL 也认为那些块是满的。这就是第 10 章要讲的「越用越慢」的物理根源。

3.3 预留空间的三种来源

实际能拿到的预留空间来自三个地方,它们的可控性完全不同:

来源怎么来的量级(经验)用户能控制吗稳定性
厂商固定预留出厂时把物理容量划出一部分不给用户客户端到企业级不等,档次越高越多不能,出厂即固定永久有效
单位换算差额十进制标称与二进制实际之间的差约百分之几的量级不能,行业惯例永久有效
主机主动留出分区时少分一部分,或用主机工具留出空间完全由用户决定能,且随时可改取决于使用习惯

三种来源里,只有第三种是设计者能主动调整的,也是第 8.4 节「主机管理的预留空间」要讲的内容。第一种和第二种在拿到器件时就已经确定了,选型时能做的只有「选哪一档」。

需要提醒的是:单位换算差额这一项经常被人误当成预留空间全部。它确实存在,但量级只有几个百分点,对高写入负载来说远远不够。真正起决定作用的是厂商固定预留与主机主动留出这两项。

3.4 与备用区的区别

「预留空间」和「备用区(spare area / over-head)」是完全不同的两件事,混用会让容量账算错:

对比项预留空间 OP备用区 / 冗余区
存在位置整块的富余容量,以块为单位每个页内部的附加字节,以字节为单位
用途给回收搬迁用,降低写放大存 ECC 校验码与元数据,保证数据正确
能不能省能省,但写放大与性能会恶化不能省,是数据可靠性的必需品
主机能感知能,表现为标称容量变小不能,完全隐藏在页结构内
与寿命的关系越大越省寿命(写放大低)越大越可靠(纠错能力强)
典型规模用户容量的百分之几到几十个百分点每页几十到几百字节(随页大小与工艺)

一句话区分:备用区是「为了让数据读得对」,预留空间是「为了让盘写得动、写得久」。两者都占用物理容量,但作用机理毫不相干,不能在容量预算里互相抵扣。

还有一个容易混的概念是坏块替换池:它也是以块为单位的富余容量,但用途是替换出厂坏块与使用中出现的新坏块,属于可靠性冗余,不能拿来当回收的周转空间——用掉了就没有替换余量了。

3.5 预留空间从哪里来

把上一节的结论收拢成一张可执行的清单。做方案时按这个顺序问自己,就能知道这颗盘实际有多少回旋余地:

  1. 出厂固定预留是多少?查规格书或问原厂,客户端盘与企业级盘在这一项上通常差一个档次。
  2. 单位换算带来多少?十进制标称与二进制实际之间的差,量级几个百分点。
  3. 固件开销吃掉多少?映射表、日志、固件镜像都要占块,小容量盘占比更高。
  4. 主机打算再留多少?这是唯一能主动加的一项,也是成本最高的一项(要牺牲可用容量)。
  5. 负载会不会写满?写满一次,第 2 节说的等效预留就归零,前面四项里真正生效的只剩前三项。
同一个容量,两种口径:分母用错了,两个数字能对不上 25%物理容量(裸容量)C_rawNAND 上真实存在的全部可擦除块用户可见容量 C_user预留空间 OP口径一(行业常用)OP = (C_raw - C_user) / C_user本例 = 28%口径二(占物理容量的比例)OP_raw = (C_raw - C_user) / C_raw本例 = 22%两个口径换算:OP_raw = OP / (1 + OP),OP = OP_raw / (1 - OP_raw)谈预留空间之前必须先对齐分母,否则「多留 5 个点」这句话会有两种完全不同的落地结果。口径一 · 除以用户容量数值更大,行业常用本文默认用这一口径口径二 · 除以物理容量数值更小,规格书常见看材料时要先问清换算只差一个分母OP=28% 对应 OP_raw=22%差了 6 个百分点图中比例仅为示意取整,不构成任何器件的规格;实际容量关系以器件规格书给出的参数为准。
图 4 · 物理容量、用户容量与预留空间的关系条,以及两种口径的换算
一个判断小技巧

在没有规格书可查的情况下,可以用「标称容量 × (1 + 预估 OP) 约 物理容量」反推,再用实测的稳态写放大去校验:如果实测写放大明显高于同档位盘的典型区间,通常说明实际预留比预估的少,或者负载的随机度比预估的高。这个交叉验证方法在第 11.5 节会展开。

4. 预留空间如何影响回收与写放大

这是全文的核心章节。第 2 章已经得到「一次回收的写放大贡献 = V / (N - V)」,本章把这句话从单次回收推到稳态:整盘的平均有效数据占比由预留空间决定,而稳态写放大又由平均有效数据占比决定。预留空间与写放大之间因此存在一条可以直接画出来的曲线,且这条曲线是单调下降、边际递减的。

4.1 预留越大写放大越低的原因

因果链只有四步,但每一步都必须想清楚:

  1. 预留空间越大 → 整盘平均有效数据占比 u 越低。设物理容量 C_raw、用户容量 C_user,主机写满用户容量时,整盘有效数据占比 u = C_user / C_raw = 1 / (1 + OP)。OP 越大,u 越小。
  2. 平均有效数据占比越低 → 任意一个块被挑中回收时,块内的有效页越少。这是统计意义上的:整盘只有 u 比例的页是有效的,那么一个随机块的期望有效页数就是 N × u。
  3. 块内有效页越少 → 搬迁量 V 越小。这一步是第 2.3 节的结论。
  4. V 越小 → 回收的写放大贡献 V / (N - V) 越低。收工。

把 1 代入 4,就得到稳态下的那条关系式(严格来说是上界,见下一节):

稳态写放大的上界:  WA_max = 1 / (1 - u) = (1 + OP) / OP

  OP = 0.07  ->  WA_max 约 15.3
  OP = 0.15  ->  WA_max 约 7.7
  OP = 0.28  ->  WA_max 约 4.6
  OP = 0.50  ->  WA_max 约 3.0
这是上界,不是预测值

这个式子假设的是最坏情况:写入完全随机、毫无局部性、且盘被写满。真实负载几乎总是有热点局部性的——被反复改写的数据集中在少数块上,那些块会变得很脏,回收它们非常划算,于是实测写放大远低于上界。

所以正确的用法是:用上界做保守设计(最坏情况能不能接受),用实测值做验收(这颗盘实际表现如何)。两者不要混用,也不要把上界当成「这颗盘的写放大就是 15」——那会导出荒谬的寿命结论。

4.2 稳态下的量化关系

把不同 OP 档位代进上式,得到下面这张表。请注意看「上界」和「典型实测区间」两列的差别——差的就是局部性带来的收益。

OP(口径一)有效数据占比 u写放大上界 (1+OP)/OP典型实测区间(经验)适用负载形态
0%(无预留)1.00趋于无穷不可控,可能到几十不可用于随机写
7%0.93515.32 到 6客户端轻负载、有局部性
15%0.8707.71.5 到 3.5客户端主流、混合负载
28%0.7814.61.3 到 2.5企业级入门、写密集
50%0.6673.01.2 到 2.0写密集、抖动敏感
100%0.5002.01.1 到 1.5极端写密集、短寿命换性能

这张表有两个用法:

  • 正向:已知预留多少,估算最坏写放大,再估算寿命够不够。
  • 反向:已知寿命目标与写入量,反推需要多少写放大,再反推需要多少预留。

反向用法在选型时更常见,第 9.2 节会给出完整的反推步骤。此处先强调一点:写放大同时决定性能与寿命,所以这张表既是性能表也是寿命表。

4.3 突发与稳态的差别

上界公式描述的是稳态——盘已经被写满、且持续被随机改写很长时间之后的状态。但实际负载往往不是稳态的,把这两种状态分开看非常重要:

状态盘的实际情况写放大表现性能表现持续时间
初始态大量块从未写过,处于已擦除状态接近 1,几乎无回收最快,延迟最低直到盘被写满一次
突发态短时间内大量写入,空闲块快速消耗暂时不高,但水位急剧下降先快后慢,出现拐点突发持续期间
过渡态后台回收追赶不上消耗逐步上升抖动开始出现数十秒到数分钟量级
稳态所有块都含过数据,回收持续进行稳定在上界与实测值之间稳定但低于初始态长期
劣化态接近写满且无丢弃通知显著高于稳态明显掉速、延迟长尾直到容量释放

这里最值得注意的现象是「初始态的假象」:新盘测出来的性能非常好,因为大量块是干净的、根本不需要回收。但这个状态不可持续——盘被写满一次之后就永远回不去了(除非做一次全盘擦除类操作)。所以:

不要用新盘的测试成绩做验收标准

验收之前必须先把盘「写满一次」,让它进入稳态,再测性能。行业里的稳态性能测试流程(先把盘顺序写满、再施加随机写负载一段时间、然后开始采样)就是为这个目的存在的。

如果跳过这一步,验收得到的数字会显著好于实际长期表现,投产之后才会暴露问题。这是存储选型里最常见、代价也最高的一类误判。

4.4 边际收益递减

把 4.2 节那张表画成曲线,会看到一个非常明确的形状:OP 从 0 加到 7% 时,写放大上界从无穷掉到 15,收益巨大;OP 从 28% 加到 50% 时,只从 4.6 掉到 3.0,收益很小。这就是边际收益递减。

OP 区间上界变化单位预留换来的收益还值得加吗判断
0% → 7%无穷 → 15.3极大必须加不加根本不能用
7% → 15%15.3 → 7.7很大强烈建议性价比最高的一档
15% → 28%7.7 → 4.6中等看负载写密集场景值得
28% → 50%4.6 → 3.0较小只在特定场景抖动敏感或极端写密集
50% → 100%3.0 → 2.0很小几乎不值得容量成本太高

递减的原因从公式看一目了然:(1 + OP) / OP = 1/OP + 1。OP 越小,1/OP 这一项变化越剧烈;OP 越大,它被稀释得越厉害。当 OP 已经很大时,再往上加只能把那条「1」以外的部分再压一点点。

因此「预留越多越好」是错误的。正确的判断是:先看负载的写密集程度与抖动敏感度,找到边际收益开始变平的那个拐点,把预留定在它附近。第 9.5 节会给一个决策框架。

4.5 典型档位与效果量级

把行业里常见的几档预留和它们的实际效果放在一起,作为选型的起点。再次强调:这些都是量级与经验区间,不是任何一颗料的规格。

档位典型 OP面向的场景为什么这么定代价
客户端入门约 7% 上下日常办公、轻负载容量敏感,成本优先随机写密集时掉速明显
客户端主流约 15% 上下混合读写、日常重度使用容量与性能的折中点标称容量少一档
企业级入门约 28% 上下读多写少、有写突发保证稳态性能不塌每 GB 成本上升
企业级写密集约 50% 上下或更高日志、数据库、缓存抖动必须压到很低容量成本大幅上升
主机自定义由分区方案决定特殊负载与定制系统按实测反馈调整需要自己维护与验证

一个常被问到的问题是「能不能靠主机少分区来替代厂商预留?」答案是物理上可以,工程上不推荐完全替代:厂商预留是出厂就划定的、不会被误用;而主机留出的空间依赖使用习惯,一旦有人把分区建满,预留就消失了。稳妥做法是两者叠加——出厂预留打底,主机再根据需要加一层。

稳态写放大上界随预留空间下降:前 15 个点收益最大,之后明显变平201510500%10%20%30%40%50%预留空间 OP(口径一,占总用户容量的比例)纵轴:稳态写放大上界 WA_max(倍)虚线 1 对应 OP = 7%,上界约 15.3虚线 2 对应 OP = 28%,上界约 4.6曲线是上界不是预测值真实负载因局部性会更低前段陡,后段平边际收益递减非常明显OP 为 0 时发散没有预留就没有稳态可言
图 5 · 预留空间与稳态写放大上界的关系曲线(示意,曲线为理论 上界)

图 5 把这条曲线画了出来。请特别注意曲线的形状——它在左侧几乎是垂直下降的。这意味着:从「几乎没有预留」到「留够十几个百分点」这一段,是投入产出比最高的区间;再往上加,曲线迅速变平。

本章要点小结

预留空间与写放大之间通过「整盘有效数据占比」这座桥连接起来:OP 决定 u,u 决定回收时的平均搬迁量 V,V 决定写放大。这条链条上没有任何魔法,全是算术。理解了这条链,就能自己推导任何一组输入下的结果,而不必去背「某某档位要留多少」这种结论。