1. 引言:为什么写放大问题重新回到舞台中央
过去十年,闪存技术发展的主旋律是“更快、更密、更便宜”。容量从SLC一路演进到MLC、TLC、QLC,接口从SATA升级到PCIe 4.0、5.0甚至6.0,随机读写性能提升了几个数量级。然而有一只看不见的手一直在制约着闪存系统的真实表现,它就是写放大。
写放大(Write Amplification,简称WA)并不是一个新概念。早在机械硬盘时代,文件系统元数据更新、数据库事务日志、虚拟内存换页等机制都会产生额外的物理写入,但当时的写放大通常只有几倍,而且机械硬盘没有擦写寿命问题,用户感知不强。进入固态硬盘时代后,写放大对系统的影响被急剧放大:一方面,NAND闪存的物理特性决定了小粒度写无法直接落盘,垃圾回收会搬移大量有效数据;另一方面,闪存单元存在有限的擦写次数,写放大每增加一倍,意味着寿命近似缩短一半,同时稳态性能也会因为后台搬移而显著下降。
对数据中心来说,写放大直接转化为成本。如果一块盘的写放大系数是3,意味着主机只写了100GB数据,闪存内部却实际写入300GB。多出来的200GB不仅消耗了宝贵的擦写寿命,还占用了控制器、总线和后台任务的资源。在云厂商动辄部署数十万块SSD的场景下,把平均写放大系数从3降到2,就相当于凭空多出三分之一的有效寿命,这是任何采购谈判都难以达到的成本优化效果。
正因为如此,写放大优化一直是学术界和工业界共同关注的话题。早期的优化主要集中在SSD控制器内部的FTL算法上,包括更精细的地址映射、更聪明的垃圾回收和更均衡的磨损管理。随后人们发现,仅靠控制器“猜”数据的冷热属性并不够,主机侧的信息才是关键,于是出现了TRIM、多流写等让主机参与数据放置的机制。最近几年,随着QLC普及、ZNS分区命名空间走向商用,以及NVMe规范家族引入灵活数据放置FDP,“写放大优化策略是否需要走向统一标准”这个问题被正式摆上了台面。
本文试图回答几个层层递进的问题:写放大从何而来,现有优化策略各自解决什么问题,标准化进展到了哪一步,不同路线之间是竞争关系还是互补关系,以及未来是否会出现真正意义上的统一标准。全文约2万字,读者可以先通过目录快速定位到自己关心的章节。
2. NAND闪存的物理约束与写放大的本质
2.1 页、块与写前擦除
理解写放大,必须先理解NAND闪存的物理组织方式。NAND芯片由大量存储单元组成,按照层级可以划分为晶圆、平面、块和页。其中与写放大直接相关的是块和页:页是读写的最小单位,通常为4KB、8KB或16KB;块是擦除的最小单位,通常包含数百个页,容量在几MB到十几MB之间。
NAND闪存有一个与磁盘截然不同的特性:写入之前必须先擦除。对SLC、MLC、TLC等电荷捕获型闪存而言,编程操作只能把单元从“1”变为“0”,而擦除操作才能把单元恢复为“1”。这意味着数据无法像在磁盘上那样原地覆盖,任何逻辑上的修改都必须写到新的物理位置,旧位置需要先经过块级擦除才能重新使用。
由于页和块的粒度差异巨大,一个看似微小的更新也可能引发连锁反应。例如,主机修改了一个4KB页,FTL需要把这个页写到某个空闲块中,原页所在位置被标记为无效,等待垃圾回收。随着写入不断进行,闪存中会出现大量“部分有效、部分无效”的块,这些块无法直接擦除,因为里面还保存着仍然有效的数据。
2.2 逻辑地址到物理地址的映射
为了屏蔽闪存的这些限制,固态硬盘内部引入了闪存转换层(Flash Translation Layer,简称FTL)。FTL的核心职责是维护逻辑块地址到物理块地址的映射表,让操作系统仍然以为自己面对的是一个可以随机覆盖写的块设备,而实际上所有写入都被重定向到新的物理位置。
FTL的映射粒度通常有三种:页级映射、块级映射和混合映射。页级映射把每个逻辑页都映射到一个独立的物理页,灵活性最高,但映射表本身会占用大量内存;块级映射以块为单位建立映射,内存占用小,但会放大写放大,因为即使是小更新也需要整个块参与搬移;混合映射在两者之间折中,把闪存空间划分为数据区和日志区,小更新先写入日志区,再由后台合并回数据区。
无论采用哪种映射方案,FTL都必须在某个时刻处理“无效页堆积”的问题。这就是垃圾回收。垃圾回收选择一个包含较多无效页的块,把其中仍然有效的页搬移到新的空闲块中,然后擦除整个旧块。被搬移的有效页数量,正是写放大的主要来源。
2.3 写放大的数学定义
写放大系数通常用WAF(Write Amplification Factor)表示,定义为闪存内部实际完成的物理写入量除以主机发出的逻辑写入量。公式为:WAF等于NAND物理写入总量除以主机逻辑写入总量。在理想情况下,主机写多少数据,闪存就只写多少数据,WAF等于1;但在实际系统中,由于垃圾回收搬移、元数据更新、磨损均衡搬移等原因,WAF通常大于1。
严格来说,WAF的定义中还应该区分主机可见写入和闪存媒体写入。主机可见写入可以通过SMART属性中的“Total LBAs Written”获取;闪存媒体写入则需要通过厂商提供的媒体磨损统计或NVMe日志页获取。两者相除即可得到近似的WAF。
写放大带来的代价是双重的。第一是寿命损耗:如果一块TLC盘的标称耐久度是600TBW,而它的平均WAF是3,那么主机侧实际只能写入大约200TB,其余400TB都消耗在内部搬移上。第二是性能损耗:垃圾回收搬移数据时,会占用闪存通道的读写带宽、控制器的计算资源,并且与前台主机请求争抢资源,导致延迟尖峰和吞吐下降。这解释了为什么很多SSD在写入一段时间后会从“空盘性能”跌落到“稳态性能”,两者之间的差距很大程度上就是写放大及其后台活动造成的。
2.4 一个简单的写放大示例
假设一个SSD的每个物理块包含100个页,主机进行完全随机的小块写入,把整个用户空间写满一遍。最初,所有块都是空闲的,写入过程接近于顺序写,WAF接近1。但当所有块都被写满后,后续的每一次4K写入都需要触发垃圾回收:FTL找到一个块,它里面可能还有90个有效页、10个无效页,为了回收这10个页的空间,FTL必须先把90个有效页搬移到新块,再擦除旧块。
在这个稳态下,主机每写入10个页的新数据,闪存内部就要额外搬移90个页的旧数据,加上新数据本身,物理写入量是逻辑写入量的10倍,WAF约为10。这个数字会随着无效页比例、预留空间大小、随机程度和负载模式的不同而变化。预留空间越大,每个块在稳态下的平均无效页比例越低,搬移量越少,WAF也越低,这就是预留空间能够改善写放大的根本原因。
3. 写放大的量化和测量方法
3.1 从SMART和日志获取原始数据
精确测量WAF的第一步是同时获取主机写入量和闪存媒体写入量。对于SATA盘,可以通过SMART属性读取主机写入量,通常位于属性F1或F9,单位因厂商而异;闪存媒体写入量则可能体现在属性EA、F1扩展或其他厂商自定义属性中。对于NVMe盘,主机写入量可以通过SMART/Health Information日志页中的Data Units Written获得,媒体写入量则可能需要读取厂商特定的日志页。
需要特别提醒的是,不同厂商对“主机写入量”和“NAND写入量”的定义并不完全一致。有些统计只包含用户数据,有些则把元数据也计入;有些按4KB逻辑块计数,有些按512字节或32MB粒度计数。因此,直接比较不同厂商盘的WAF数值时需要格外谨慎,应先核对统计口径。
3.2 典型测试负载设计
WAF是工作负载的函数,同一个盘在不同负载下的WAF可以相差数倍甚至数十倍。常见的测试负载包括:完全顺序写、完全随机写、混合读写、热点随机写、数据库型负载等。要评估一块盘的写放大特性,至少应该在空盘写入、满盘稳态、预留空间不同比例等条件下分别测试。
对于随机写测试,通常先对全盘做一次预写入使得盘进入稳态,然后持续写入固定数据量,记录主机写入量和媒体写入量,计算稳态WAF。对于混合负载,需要用固定比例的读写混合,并统计足够长的时间窗口。对于数据库负载,可以借助fio的libaio引擎模拟提交延迟和批量写入,也可以直接使用真实数据库跑标准基准测试。
下面是一个使用fio测量NVMe盘随机写WAF的简要示例,实际使用时需要根据设备路径和日志页调整参数:
# 1. 预先填满全盘,使其进入稳态 fio --name=prefill --filename=/dev/nvme0n1 --ioengine=libaio \ --rw=randwrite --bs=4k --size=100% --direct=1 --numjobs=8 \ --iodepth=32 --group_reporting 2. 记录当前SMART中的主机写入量和媒体写入量 nvme smart-log /dev/nvme0n1 | grep -E "data_units_written|media" 3. 进行指定时长的稳态随机写 fio --name=steady --filename=/dev/nvme0n1 --ioengine=libaio --rw=randwrite --bs=4k --size=100% --direct=1 --numjobs=8 --iodepth=32 --runtime=3600 --time_based --group_reporting 4. 再次读取SMART,计算两次差值之比 nvme smart-log /dev/nvme0n1 | grep -E "data_units_written|media"3.3 WAF与性能的关联
写放大不仅表现为寿命消耗,也会通过后台活动影响前台性能。在稳态随机写测试中,高WAF的盘往往表现出更低的持续带宽和更高的尾部延迟。因此,仅关注峰值性能是不够的,稳态性能和延迟分布同样重要。
评估时可以同时采集三项指标:主机写入带宽、内部媒体写入带宽以及队列深度下的延迟百分位。如果主机写入带宽随时间明显下降,而媒体写入带宽维持在高位,说明后台垃圾回收正在大量搬移数据,这是WAF恶化的典型信号。
4. 写放大的主要来源
4.1 垃圾回收搬移
垃圾回收是写放大最直接、最主要的来源。当一个块的无效页比例超过一定阈值时,FTL会启动回收流程:读取块内所有仍然有效的页,将它们写入新的空闲块,然后擦除旧块。搬移的有效页越多,写放大越大。
垃圾回收的成本与无效页密度直接相关。如果回收一个几乎完全无效的块,只需要搬移极少有效页,代价很低;如果回收一个大部分仍有效的块,代价就很高。因此,FTL的目标是尽量让数据按照冷热程度分开存放,使冷数据块和热数据块各自聚集,这样回收时可以优先回收热数据块,因为热数据块中的无效页比例通常更高。
4.2 磨损均衡引发的搬移
磨损均衡机制也会引入额外的写放大。为延长整块盘的使用寿命,FTL会尽量让所有物理块的擦写次数保持均衡。对于长期保持不变的数据,即所谓的静态数据,如果它一直占用某些擦写次数很少的块,就会造成磨损不均。静态磨损均衡会主动把这类冷数据搬移到已经磨损较严重的块上,把磨损较轻的块腾出来接收热数据。
这种搬移是纯内部行为,不增加主机可见的有效数据,却增加了内部写入量,因此也是写放大的来源之一。好在健康系统的磨损均衡搬移占比通常不高,其影响远小于垃圾回收。
4.3 元数据和映射表更新
FTL需要持久化映射表、块状态、日志等元数据。对于页级映射,映射表规模很大,例如一块1TB盘采用4KB粒度映射,映射表条目数量可达数亿条。每次写入都会修改映射关系,这些修改本身也会写入闪存,并触发额外的垃圾回收,形成二次写放大。
为了控制元数据开销,现代SSD通常采用多种技术:映射表分层、增量日志、掉电保护缓存合并,以及利用主机内存缓冲的HMB机制。这些技术能够把元数据写入压缩到合理范围,但无法完全消除它的写放大贡献。
4.4 小写入与页内填充
当主机写入的粒度小于物理页大小时,就会产生页内碎片问题。例如,物理页是16KB,主机却只写了4KB,FTL通常无法把多个不相关的4KB小写合并到同一个物理页并分别更新,因为每个物理页只能完整写入一次。一旦后续某个4KB部分需要更新,整页数据可能需要搬移。
这种小写入场景在数据库redo日志、元数据更新、随机键值操作中非常常见。为了缓解页内碎片,一些SSD会采用页内地址压缩、部分页编程或者缓存聚合技术,但效果受限于物理页的可编程约束。
4.5 后台任务和错误处理
除了垃圾回收和磨损均衡,后台任务还包括读干扰数据刷新、数据保留时间管理、坏块预留区补充、掉电恢复数据校验等。这些任务都会产生内部写入,虽然单项占比不大,但在写密集型场景下叠加起来也不可忽视。尤其是QLC等新型介质,其读干扰和保持时间问题更突出,后台刷新频率更高,这部分写放大有上升趋势。
5. 控制器侧优化:FTL与垃圾回收的持续进化
5.1 映射粒度与映射表管理
页级映射能够把写放大降到最低,因为它允许FTL以最小粒度灵活分配物理位置。早期受限于内存成本,许多消费级盘采用块级或混合映射,牺牲了一定的随机写性能。如今随着DRAM和SRAM成本下降,以及HMB主机内存缓冲的普及,高端盘普遍采用页级映射,低端盘也在向细粒度映射演进。
映射粒度并非越小越好。过细的粒度意味着更大的映射表和更高的元数据写入频率;过粗的粒度则意味着更频繁的搬移。选择映射粒度需要在DRAM容量、控制器算力、写入负载特征和WAF之间寻找平衡。
5.2 冷热数据分离
冷热数据分离是控制垃圾回收成本的关键手段。其基本思想是:频繁更新的热数据和不常更新的冷数据应该分别存放在不同的擦除单元中。这样,热数据块中无效页比例上升得快,可以低成本回收;冷数据块则长期保持稳定,不会被频繁搬移。
实现冷热分离可以在多个层面进行。FTL内部可以通过统计逻辑地址的更新频率来推断冷热属性;主机侧可以提供显式的流或放置提示;文件系统和数据库也可以直接把冷热信息传递给存储栈。单纯依靠FTL内部统计存在滞后性和误判风险,而显式提示通常更准确,这也是多流写和FDP等标准出现的动因。
5.3 垃圾回收策略与时机
垃圾回收策略的核心问题是“何时回收”和“回收哪一块”。回收太早,有效页搬移量大,浪费带宽;回收太晚,空闲块不足,前台写入被迫等待,产生延迟尖峰。
工程上常用的策略是设置空闲块水位线:当空闲块数量低于低水位时启动回收,高于高水位时暂停回收。选择回收块时,通常采用贪心策略或成本收益策略。贪心策略选择无效页最多的块,能立即回收最多的空间,但可能错过对长期WAF更有利的目标;成本收益策略则综合考虑块的使用时间、无效页比例、擦写次数等因素,避免过早搬移仍然较“年轻”的数据。
此外,现代的垃圾回收还普遍引入“预清理”和“后台清扫”机制。优先在主机负载较低时提前回收,把垃圾回收从突发性、抢占性的行为转变为平滑的后台任务,降低对前台延迟的影响。
5.4 磨损均衡的精细化
磨损均衡策略直接影响WAF。动态磨损均衡只在新写入分配块时考虑擦写次数,不搬移已有冷数据,搬移成本低,但当数据冷热分布长期不均时,块间磨损差异会增大。静态磨损均衡会把冷数据搬移到磨损较多的块上,能够获得更均匀的磨损分布,但会引入额外的搬移写放大。
现代控制器通常按块管理磨损,并设置阈值:当块间擦写次数差异超过阈值时,触发静态磨损均衡。同时,控制器会把冷数据识别与静态磨损均衡结合起来,优先搬移那些长期不更新的数据块,减少重复搬移。
5.5 预留空间OP的作用
预留空间(Over-Provisioning,简称OP)指SSD内部保留的、不向主机暴露的闪存容量比例。用户可写的逻辑容量小于物理闪存容量,差值就是OP。一块标称1TB的消费级盘,物理容量可能是1024GiB,若用户容量为1000GB,则OP约为7%;企业级盘通常配置更高的OP,如28%甚至更高。
OP对WAF的影响非常显著。更高的OP意味着稳态下每个块的无效页密度更低,垃圾回收需要搬移的有效页更少。经验上,把OP从7%提高到28%,完全随机写负载下的稳态WAF可以从接近10降到2到3的水平。OP的代价是用户可用容量变小,单位容量成本上升,因此需要在寿命、性能和成本之间平衡。
下面给出一个经验性的OP与稳态随机写WAF关系示意表,数值因厂商和盘型不同而有所浮动:
| 预留空间比例 | 典型空盘随机写WAF | 典型稳态随机写WAF | 说明 |
|---|---|---|---|
| 7%左右 | 1到2 | 6到12 | 常见消费级客户端盘 |
| 15%左右 | 1到1.5 | 4到7 | 轻度企业负载 |
| 28%左右 | 约1 | 2到3 | 写密集型数据中心盘 |
| 50%及以上 | 约1 | 1.2到2 | 特种高耐久写入盘,成本较高 |
5.6 压缩与去重
部分企业盘内置数据压缩和去重引擎。压缩能够在写入前减少数据体积,从而直接降低物理写入量;去重则可以避免相同数据的重复写入。这两种技术都相当于在主机不可见的情况下降低了闪存的实际负载,对WAF有正面的贡献。
不过,压缩和去重会增加控制器复杂度,并对延迟产生影响,且在已压缩数据、加密数据等场景下收益有限。不同负载下的效果差异很大,使用前需要通过真实工作负载评估。
6. 主机侧优化:操作系统、文件系统与应用配合
6.1 TRIM、Discard与Deallocate
TRIM是最早被广泛采用的主机侧写放大优化机制。它的核心逻辑很简单:当文件系统删除文件时,通过TRIM命令通知SSD哪些逻辑区域已经不再使用,SSD可以立即把对应物理页标记为无效,而不是等到后续覆盖写时才被动发现。
在SATA接口上,该命令被称为TRIM,对应ATA的DATA SET MANAGEMENT命令;在SCSI/SAS上称为UNMAP;在NVMe上称为Deallocate,通过Dataset Management命令实现。Linux系统中,TRIM可以通过挂载参数discard自动执行,也可以通过fstrim工具定期批量执行。异步批量TRIM通常比每次删除都透传更高效,避免大量小命令拖累性能。
TRIM的意义在于把“数据已无效”这一上层信息传递给FTL,使垃圾回收不必搬移已经无用的数据。没有TRIM时,文件系统删除操作对SSD完全不可见,FTL会认为所有写过的地方都仍然有效,导致无效页迟迟无法被识别,GC成本大幅上升。
6.2 文件系统与SSD的协同
传统文件系统基于磁盘原地覆盖的假设设计,很多行为在闪存上并不友好。例如,频繁的元数据小写会触发票内碎片和映射表压力。现代Linux文件系统如ext4、XFS、Btrfs都针对闪存做了优化:ext4支持延迟分配和批量写回,XFS的分配组设计也利于顺序化,Btrfs则通过写时复制和extent管理减少随机小写。
日志结构文件系统在设计理念上与闪存天然契合。F2FS就是专为NAND闪存设计的文件系统,它把写入组织为顺序日志,配合多流写或冷热分离可以显著降低WAF。在嵌入式设备、移动终端和部分服务器场景中,F2FS被广泛采用。
6.3 I/O调度与写合并
块设备层面的I/O调度器也会影响写放大。调度器可以把相邻的小写请求合并为大写请求,减少Flash的写粒度损耗;也可以通过请求重排减少读写之间的冲突。对于NVMe盘,Linux内核通常采用多队列调度或直接透传策略,因为NVMe设备处理请求的能力很强,过度的软件调度反而可能增加延迟。但对于SATA设备,传统的合并和排序仍有价值。
应用层可以使用诸如io_uring、SPDK等接口绕过页缓存和调度器,直接管理I/O。这类方案强调低延迟和高吞吐,但应用需要自行承担部分数据放置和写合并的责任。在追求极致WAF的场景中,应用层直通配合设备侧数据放置提示,是目前最有效的组合之一。
6.4 数据库层的写放大
数据库系统本身存在多级写放大:应用写入到数据库、数据库写redo日志、redo落盘、数据页刷盘、checkpoint、LSM树压缩等。对于跑在SSD上的数据库,选择合适的数据结构和刷盘策略对整体WAF影响巨大。
以RocksDB这类LSM树数据库为例,最耗写放大的是后台compaction,它反复读写同一批键值数据。通过调整level数量、compaction策略、绑定不同等级文件到不同流或放置提示,可以把compaction的低价值写入与前台高价值写入分离,从而降低对SSD的物理磨损。RocksDB社区也在积极适配ZNS和FDP等新特性。
7. 多流写:主机提示机制的开端
7.1 背景与动机
控制器内部推断冷热数据存在信息不对称的问题。主机知道一个写入请求来自哪类应用、哪个文件、哪次compaction,但FTL只能看到逻辑地址和时序。如果主机能够把这些信息告诉SSD,SSD就能更准确地把相似生命周期的数据放在一起。多流写(Multi-stream Write)就是为实现这一目标而提出的机制。
多流写的思路是:主机为每个写入请求附带一个流标识(Stream ID),相同流的数据被认为具有相似的生命周期,SSD应将它们尽量放在相同或相邻的擦除单元中。这样,当一个流中的数据失效时,它们所在的块中无效页比例会更集中,垃圾回收成本更低。
7.2 多流写的实现方式
多流写最早在SATA生态中被提出,后来进入NVMe 1.4规范的Directives机制。SATA实现的Streams允许主机通过命令中的Stream ID字段标记写入,设备可以暴露支持的流数量。NVMe的Streams Directive则通过Directive Type和Streams标识实现类似功能。
设备端通常会维护若干流,每个流拥有独立的写入缓冲区。相同流的数据尽量写往相同目标块,不同流之间避免混合写入同一个块。当某个流的无效比例足够高时,优先回收该流对应的块。主机需要负责流的分配和生命周期管理,例如把数据库日志、表数据、临时文件分别分配不同流。
/* NVMe Streams 使用示意(伪代码) */ struct nvme_rw_command cmd = {0}; cmd.opcode = nvme_cmd_write; cmd.nsid = nsid; cmd.slba = lba; cmd.length = sector_count; cmd.control = cpu_to_le16(NVME_RW_DIRECTIVE_STREAMS); cmd.stream_id = stream_id; /* 0..max_streams-1 */ submit_io(&cmd);7.3 多流写的局限
多流写虽然理念清晰,但在实际部署中并未大规模普及,原因主要有几点。第一,应用改造代价高,数据库、文件系统、虚拟化软件都需要显式管理流ID,生态推进困难。第二,流数量有限,而真实工作负载的生命周期种类远多于流数量,分配和回收策略复杂。第三,多流写对设备内部调度提出新要求,如果控制器处理不当,多个流之间的竞争可能导致性能下降。
此外,多流写在SATA和NVMe上长期处于“标准存在但生态不完整”的状态。主流操作系统内核对流式写入的支持有限,应用层也缺乏统一接口。多流写更像是证明了“主机提示能够降低WAF”这一理念的可行性,但尚未形成足以改变行业的统一标准。
尽管如此,多流写的研究和试点为后来的FDP铺平了道路。可以说,FDP在理念上继承了多流写,但在接口设计和工程友好度上做了大幅改进。
8. ZNS:分区命名空间的激进方案
8.1 ZNS的基本概念
如果说多流写是温和改良,那么分区命名空间(Zoned Namespaces,简称ZNS)就是相当激进的变革。ZNS由NVMe TP4053引入,并成为NVMe 2.0规范家族的一部分。在ZNS中,逻辑地址空间被划分为若干固定大小的分区(Zone),每个分区只能顺序写入,并且只能以分区为单位擦除或重置。
ZNS的思想本质上是把FTL原本对主机隐藏的闪存约束部分暴露出来。既然闪存本来就是顺序写、块擦除,干脆要求主机也按照同样的规则使用设备,这样设备端的地址映射可以大幅简化,甚至不需要为每个4K逻辑块维护映射关系,只需维护每个分区的写指针和偏移。
传统SSD里由控制器负责的数据放置、垃圾回收、磨损均衡等任务,在ZNS盘上被部分上移给主机或文件系统。主机按照分区顺序写、写完一个分区再写下一个,分区删除时向盘发送Reset Zone命令,整个分区被擦除,成为新的空闲分区。
8.2 ZNS如何降低写放大
ZNS可以大幅降低写放大的原因在于,它让写入模式天然贴近闪存的物理特性。顺序写意味着写指针连续推进,几乎没有页内碎片;分区整体擦除意味着不存在“从混杂块中搬移有效页”的垃圾回收过程,设备端不再因为搬移旧数据而重复写入。
在理想的应用配合下,ZNS盘的WAF可以非常接近1。设备端只需要处理介质管理、坏块替换和磨损均衡等少量任务,不再维护庞大的逻辑到物理映射表和复杂的GC状态。这不仅降低写放大,还节省了控制器内存和算力,降低了单位容量成本,这也是ZNS在云端大容量场景中备受关注的原因。
8.3 软件栈改造的代价
ZNS的代价主要转嫁到了软件层。传统文件系统假设块设备支持随机覆盖写,而ZNS要求写入严格顺序、擦除按分区进行,两者并不兼容。为此,Linux社区引入了zonefs文件系统,它把每个分区暴露为一个顺序文件,适合日志型应用;F2FS也增加了ZNS支持;RocksDB则通过ZenFS插件在ZNS盘上管理数据放置。
对上层应用来说,使用ZNS盘需要感知分区语义。一般做法是把设备划分为运行普通文件系统的传统分区和暴露ZNS特性的分区命名空间,传统应用继续使用传统盘,而高写入、日志型、顺序友好的应用迁移到ZNS。这种混合部署降低了迁移门槛,但也增加了运维复杂度。
8.4 适用场景与限制
ZNS最适合顺序写比例高、数据可以按时间或批次自然管理的工作负载,例如日志存储、事件流、对象存储、备份归档、LSM树数据库的WAL和SST文件等。相反,对完全随机写、需要大量原地覆盖的工作负载,ZNS不仅没有优势,还会因为分区写指针管理和Reset Zone操作带来性能损失。
ZNS盘的容量越大,分区越多,主机侧的管理复杂度也越高。如何在大规模部署中高效地管理数百万个分区、处理写指针恢复、掉电一致性以及多租户隔离,仍然需要软件生态继续成熟。
8.5 ZNS的标准化状态
ZNS在NVMe生态中已经形成了正式标准,Linux内核、SPDK、fio等关键组件都提供了支持。多家厂商已经推出或示范了ZNS盘。不过,ZNS目前更偏向特定场景的技术选项,而不是对所有工作负载都适用的通用方案。它说明了一种重要趋势:写放大优化可以通过改变主机与设备之间的“接口契约”来实现,而不仅仅是控制器内部优化。
9. 灵活数据放置FDP:当前最接近统一的方案
9.1 FDP的动机
灵活数据放置(Flexible Data Placement,简称FDP)是NVMe规范家族在数据放置方面的新一代机制,由TP4146引入。它的设计目标非常明确:在保留传统SSD随机写能力和生态兼容性的前提下,让主机能够以简单、灵活的方式向设备提供数据分组提示,从而获得接近“理想数据放置”的写放大收益。
FDP可以看作是吸收了多流写经验教训后的重新设计。多流写失败的一个重要原因是流语义过于固定、主机分配负担重;FDP则采用“提示”的方式,主机只需要在写入命令中附带一个简单的放置标识,设备内部根据标识决定数据如何放置。主机提示准确,设备就能放得好;主机不给提示,设备就退化为传统SSD。
9.2 FDP的工作方式
FDP引入了Reclaim Unit(RU)和Reclaim Unit Handle(RUH)的概念。一个Reclaim Unit是设备内部用于垃圾回收的基本擦除单元集合,可以理解为设备端可独立回收的物理区域。设备会向主机暴露可用的RUH数量,主机在写入命令的Dword 12中携带一个RUH值,表示这个写入希望被放置到哪个回收单元集合中。
FDP的优点在于接口简单。主机只需要通过Identify和Set Feature/Mgmt命令查询并配置FDP能力,然后在写入时附加一个索引值,不需要理解设备内部如何实现数据放置。设备可以把不同RUH的数据放到不同擦除单元中,减少后续回收时的搬移。主机则可以利用这一机制把cold数据、warm数据、hot数据分开,把数据库日志与表文件分开,甚至把不同租户的数据分开。
/* NVMe FDP 写入示意(伪代码,具体字段以规范为准) */ struct fdp_write_context { uint16_t placement_id; /* 对应 RUH */ uint32_t dword12; /* 包含 FDP 放置信息的命令字段 */ }; build_fdp_dword12(&ctx.dword12, RUH_HOT_DATA); nvme_submit_write(nsid, slba, nlb, buffer, ctx.dword12);9.3 FDP与传统盘和ZNS的对比
FDP与传统SSD的最大区别是主机可以向设备传递放置提示;FDP与ZNS的最大区别是FDP并不要求主机进行严格的分区顺序写。在FDP盘上,主机可以像以前一样随机写任意LBA,只是可以额外指定数据分组。这让FDP的迁移成本显著低于ZNS,绝大多数已有应用无需改动就能工作,有新需求的应用可以通过少量代码启用FDP提示。
从写放大角度看,FDP本身不会把WAF降到1,因为设备仍然需要垃圾回收和磨损均衡。但只要主机提示合理,FDP可以减少跨生命周期数据的混杂,从而把WAF从传统随机写的高位显著压低。对于没有ZNS迁移能力、又希望改善写放大的大数据场景,FDP是一条现实路径。
9.4 FDP的标准化和生态现状
FDP在NVMe 2.0及后续演进中得到定义,Linux内核正在增加对FDP的暴露和配置支持,SPDK也被认为是率先落地FDP的软件栈之一。多家存储厂商已经展示或规划了支持FDP的企业盘。随着NVMe 2.0逐渐普及,FDP有望成为主机侧数据放置的主流接口。
值得注意的是,FDP强调“提示”而非“强制”,主机提示的质量直接决定收益大小。因此,FDP的普及不仅取决于设备支持,还取决于文件系统、数据库和应用是否愿意主动利用这一提示。这也是FDP标准化进程中需要持续推进的生态工作。
10. 标准全景图:NVMe、SATA、SCSI的写放大相关特性
10.1 三大协议栈的写放大特性盘点
写放大优化相关的标准化工作分散在多个协议栈中。NVMe由于在数据中心的主导地位,进展最为活跃;SATA虽然仍大量存在于客户端和存量设备,但新特性推进放缓;SCSI/SAS在企业存储阵列中仍有重要地位,拥有自己的命令体系。
下表汇总了三大协议栈中与写放大优化相关的主要特性及其状态:
| 协议栈 | 特性 | 作用 | 标准化状态 |
|---|---|---|---|
| NVMe | Deallocate(Dataset Management) | 主机通知无效数据,降低GC搬移 | 已广泛采用 |
| NVMe | Write Streams(Directives) | 主机提供流提示,分离冷热数据 | 标准存在,采用有限 |
| NVMe | Zoned Namespaces(ZNS) | 顺序分区写,大幅简化FTL | 正式标准,生态推进中 |
| NVMe | Flexible Data Placement(FDP) | 灵活数据放置提示,兼容随机写 | 标准已定义,生态起步 |
| SATA | TRIM(DATA SET MANAGEMENT) | 主机通知无效数据 | 广泛采用 |
| SATA | Streams(ACS-4) | 流式写入提示 | 标准定义,实际采用极少 |
| SCSI | UNMAP | 主机通知无效数据 | 广泛采用 |
| SCSI | Streams(SBC-4) | 流式写入提示 | 标准定义,实际采用较少 |
10.2 标准不等于生态成熟
从表中可以清楚地看到,与写放大相关的特性在“纸面标准”和“实际使用”之间存在明显落差。TRIM/UNMAP/Deallocate是唯一真正标准化并大规模落地的机制,因为它的改造代价极低,操作系统和文件系统普遍支持。而流式提示类功能虽然早已进入标准,却长期缺乏生态响应。
这说明标准化的最大障碍往往不是协议文本本身,而是能否降低主机侧改造代价,以及能否让数据库、文件系统等关键软件真正使用这些接口。FDP被业界寄予厚望,正是因为它在保持兼容性的前提下提供了简单接口,为生态采纳创造了更好条件。
11. 统一标准面临的技术障碍
11.1 FTL实现差异导致优化目标不同
不同厂商的FTL内部实现差异巨大,有的偏重低延迟,有的偏重大容量,有的偏重高耐久。对于同样一个流提示或放置提示,不同盘可能采取完全不同的内部策略。这种实现差异使得“统一标准”很难规定具体的算法行为,只能规定接口和语义,而无法规定效果。
标准化组织能够定义“主机如何表达数据分组意图”,但无法强制规定“设备必须把WAF降到多少”或“必须采用某种GC算法”。如果强制规定内部行为,反而会扼杀创新,剥夺厂商在控制器算法上的差异化空间。因此,统一标准更多是接口层面的统一,而非实现层面的统一。
11.2 工作负载多样性带来的适配难题
没有一种数据放置策略能在所有负载下都最优。数据库、文件服务、对象存储、虚拟化、AI训练、流媒体等负载的读写比例、顺序性、生命周期分布差异极大。一套统一标准要覆盖所有负载,就意味着要有大量可配置参数,而参数越多,主机侧的使用门槛越高,错误配置的风险也越大。
这正是“统一标准”与“灵活适配”之间的内在矛盾。过度简化会丧失适配能力,过度复杂会阻碍生态落地。好的标准通常只定义稳定且变化缓慢的接口边界,把策略留给设备或应用自行决策。
11.3 性能可预测性与后台任务的不确定性
写放大优化往往与后台任务的调度有关。垃圾回收何时启动、搬移多少数据、回收哪些块,这些决策直接影响前台的延迟分布。如果标准试图统一这些调度行为,很可能破坏某些盘在特定负载下的性能表现。
在企业场景中,性能可预测性有时比平均性能更重要。某些优化措施虽然降低了平均WAF,却可能引入偶发的高延迟尖峰,影响服务质量。标准化需要在平均效率与尾部延迟之间留出足够的实现自由度。
11.4 数据放置提示的语义分歧
主机提供的放置提示到底代表什么?是多流写中的“生命周期组”,FDP中的“回收单元组”,还是更抽象的“服务质量类”?不同标准对提示语义的表述不完全一致。语义不统一会导致应用在跨设备、跨厂商部署时行为不一致,也给上层抽象带来了困难。
因此,未来若要进一步统一,需要先对齐语义模型。例如,明确提示是“寿命分组”而不是“性能隔离”,明确不对提示负责的设备默认行为,明确提示冲突时的处理规则。这些语义细节往往比命令格式更难达成共识。
12. 统一标准面临的产业障碍
12.1 厂商私有方案的路径依赖
在标准尚未成熟之前,许多SSD厂商已经基于私有接口或定制固件向大客户提供了写放大优化能力。大客户一旦把这种私有方案集成进自己的软件栈,迁移到公开标准就需要新的开发、测试和验证成本。部分厂商也倾向于维持私有接口以锁定客户,形成事实上的生态壁垒。
这种路径依赖会减缓统一标准的采纳速度。只有公开标准的收益明显大于迁移成本时,客户才会主动替换私有方案。这也是为什么标准化组织更希望在大规模私有方案还未扎根之前,尽早推动接口收敛。
12.2 软件生态协同的复杂性
写放大优化需要跨越硬件、驱动、操作系统、文件系统、数据库、云平台多个层次。任何一个层次的缺失都可能让整条链路断裂。例如,即使SSD支持FDP,如果Linux内核没有暴露FDP能力,如果文件系统不传递提示,如果数据库不配置分组策略,FDP就无法发挥价值。
这种跨社区协同是缓慢的。内核社区、存储厂商、数据库社区、云厂商各自有自己的节奏和优先级。标准文本可以很快发布,但要让整个软件栈真正打通,通常需要数年时间。
12.3 标准化周期与硬件迭代速度的错位
存储硬件迭代极快,而标准化组织的流程相对谨慎。一个特性从提案到正式发布,再到设备实现、OS支持、应用适配,周期往往长达三到五年。在这期间,介质技术可能已经前进一代,新的约束和优化手段又出现了。
这种时间错位要求标准具备足够的前瞻性,同时又要避免过早冻结不成熟的设计。标准的修订和演进机制因此变得非常重要,NVMe规范家族采用模块化、可扩展的形式,目的就是让新特性能够更快地进入生态。
12.4 测试认证与互操作成本
统一标准意味着需要定义一致性要求和互操作测试。不同厂商的设备、不同版本的内核、不同应用之间的组合测试工作量巨大。对于主机侧提示机制,还需要定义提示正确性、设备行为边界和性能指标,这比单纯的命令格式验证复杂得多。
如果没有明确的认证体系,标准可能只是纸上统一,各实现之间仍然存在微妙差异。而建立一个完整的认证体系,又需要标准化组织、测试机构和厂商共同投入,这需要时间。
13. 主流厂商的优化方案对比
13.1 厂商间的差异化路线
在写放大优化上,主流厂商的策略既有共性也有差异。共性在于大家都重视预留空间设计、冷热分离、精细化GC和主机提示机制;差异则体现在各家对ZNS、FDP的投入节奏,以及控制器架构和固件算法的侧重点不同。
下表是几类主流方案的定性对比,不代表具体产品的实测数据,仅用于理解路线差异:
| 厂商/路线方向 | 控制器侧重点 | 主机协同重点 | 典型适用场景 |
|---|---|---|---|
| 通用企业盘厂商 | 精细化FTL、高OP、动态GC | TRIM、直通、调度优化 | 数据库、虚拟化、混合负载 |
| ZNS先行厂商 | 分区管理、精简FTL | zonefs、ZenFS、SPDK | 日志、对象存储、顺序写密集 |
| FDP支持厂商 | RUH管理、提示驱动放置 | 内核FDP接口、应用提示 | 写密集型通用数据中心 |
| 定制化云盘厂商 | 与上层协同的私有增强 | 云存储引擎深度绑定 | 超大规模云基础设施 |
13.2 从“各自为战”到“有限收敛”
过去,写放大优化的私有属性很强,客户很难在不同厂商之间无缝切换。随着ZNS和FDP等公开标准逐步成熟,大客户开始更倾向于采用标准接口,以降低供应商锁定风险。云厂商尤其欢迎这样的变化,因为它们普遍采用多厂商采购策略,并自研存储软件栈。
可以预见,未来厂商仍会在控制器算法、固件调优、介质管理上保持差异化竞争,但对主机暴露的写放大优化接口会趋向标准化。厂商的核心竞争力将从“有没有私有接口”转向“在标准接口下谁能实现更好的WAF和性能”。
14. 实际工作负载下的写放大观察
14.1 数据库负载
在线事务处理类数据库以随机小写和频繁更新为特征,是最容易产生高WAF的负载之一。以MySQL InnoDB为例,redo日志的追加写相对顺序,但数据页的随机刷盘、双层写缓冲、undo日志等都会产生大量随机写。合理设置innodb_flush_method、innodb_doublewrite、脏页刷盘比例和I/O合并窗口,可以显著改善SSD上的写放大表现。
键值数据库和NewSQL系统普遍采用LSM树结构,写放大主要出现在compaction阶段。通过把WAL和不同层级的SST文件映射到不同流或放置提示,能够减少不同生命周期数据的混杂。这也是RocksDB等系统积极适配ZNS和FDP的原因。
14.2 虚拟化与云存储
虚拟化环境具有多层存储栈,每层都可能引入额外的写放大。虚拟磁盘内的文件系统操作、宿主机文件系统、存储虚拟化层、远端复制或快照,每一层的小写和元数据更新都会逐级放大。云存储中的分布式副本、纠删码计算、日志同步等,还会带来跨网络和跨节点的额外写入。
在这些场景中,写放大优化不仅依赖SSD本身,还依赖存储栈的协同设计。云厂商往往会在虚拟化层做写合并,在块存储层做顺序化,在SSD层启用TRIM和放置提示,尽量降低全链路写放大。
14.3 日志与对象存储
日志系统和对象存储天然具有顺序写倾向,是ZNS的优质适配场景。日志数据按时间顺序追加,旧数据按批次过期,与分区的顺序写和整体擦除高度契合。对象存储的append-only大对象写入也适合顺序化。对于这类负载,合理的软件设计甚至可以让WAF接近物理极限。
14.4 AI训练与推理
AI工作负载呈现出独特的I/O特征。训练过程以大规模随机读为主,写入相对集中在checkpoint保存和日志记录;推理服务则可能有频繁的小数据更新和缓存刷新。当前AI存储系统更多关注读带宽和并行度,写放大尚未成为首要瓶颈,但随着模型规模和数据规模继续增长,训练中断恢复、海量训练样本缓存等场景的写入压力也在上升,写放大优化会逐渐进入视野。
14.5 实测中的共性规律
综合各类负载的实测数据,可以归纳出几点规律:顺序写占比越高,WAF越低;写入粒度越大,WAF越低;主机越充分地提示无效数据,WAF越低;预留空间越大,随机写稳态WAF越低。这些规律并不因为协议或厂商的不同而根本改变,说明写放大的物理根源在闪存介质本身,标准化工作是在这些物理约束之上寻求更高效、更可移植的协作接口。
15. 工程落地建议
15.1 先量化,再优化
优化写放大之前,应该先建立可重复的测量基准。明确当前盘的WAF、稳态性能、延迟分布和耐久消耗。测量时要覆盖真实或接近真实的混合负载,而不是只测顺序写或空盘随机写。没有基线,任何优化都难以评估收益。
15.2 检查TRIM是否真正生效
TRIM是最容易落地、收益最确定的优化手段,但在多层存储栈中经常因为某个环节不支持而失效。应用需要确认从文件系统到设备驱动再到SSD整条路径上的TRIM或Deallocate都正常工作,并且被实际执行。对于使用虚拟化或容器场景,还要检查磁盘镜像格式和存储后端是否具备透传能力。
15.3 根据负载选择合适的盘型
写密集型随机负载应优先选择高OP的企业盘,并在采购时关注厂商公开的稳态随机写性能和耐久度规格。顺序写密集负载可以评估ZNS盘。对于需要通用随机写能力又希望降低WAF的场景,可以关注支持FDP的新一代盘。选型时不要把顺序读带宽作为唯一指标,稳态写入能力和WAF特性同样关键。
15.4 应用层主动配合
对于有技术能力的团队,应用层主动参与数据放置会带来最大收益。例如,数据库可以把redo日志、undo、表空间、临时表分开,不同的数据具有不同的生命周期和更新频率,将它们分流到不同设备、不同流或不同FDP提示,能有效降低物理写放大。对象存储和消息系统也可以利用ZNS的顺序分区特性重新组织写入路径。
15.5 关注下一代接口的可用性
如果软件栈基于SPDK、io_uring或自定义用户态存储引擎,可以更早地尝试FDP或ZNS。用户态存储栈的开发节奏快,受内核发行周期制约小,是新技术最先落地的平台。对于依赖成熟文件系统和数据库的企业用户,则可以等待Linux发行版和主流数据库提供正式支持后再跟进。
16. 未来展望:统一标准的可能路径
16.1 QLC、PLC时代的写放大挑战
QLC已经大规模商用,PLC正在研发推进。随着每单元存储位数的增加,闪存单元的擦写寿命进一步下降,写放大对寿命的影响变得更加突出。与此同时,更高的存储密度降低了单位容量成本,使得更高的OP配置在经济上更可行,控制器也可能分配更多资源用于GC优化。未来介质与控制器之间的协同将持续演进,写放大优化会变得更加重要而非更不重要。
16.2 计算存储带来的新可能
计算存储把一部分计算能力下沉到存储设备或存储节点,允许在数据落盘前完成压缩、过滤、聚合等处理。这相当于在更靠近介质的位置减少无效和冗余数据,天然有助于降低写放大。标准组织正在定义计算存储的接口和编程模型,未来可能与数据放置机制结合,形成更精细的写入控制。
16.3 主机与设备职责的再平衡
从FTL内部优化到TRIM、多流写、ZNS再到FDP,演进的主线是主机与设备之间的职责再平衡。传统模型下设备自主管理一切,主机完全无感知;ZNS把数据放置和回收责任大幅上移;FDP则试图在两者之间寻找中间地带,主机提供轻量提示,设备保留核心决策权。
未来最可能形成的格局是:传统SSD、ZNS和FDP三类设备长期并存,分别服务不同负载;主机侧的数据放置接口逐步向FDP这类兼容性好的机制收敛;核心协议继续以NVMe为主线,SATA和SCSI在存量生态中维持现状。统一标准并不意味着“只允许一种盘”,而是“主机可以用一套相对一致的语义面对多种盘”。
16.4 从“强制统一”到“接口收敛”
本文最核心的结论可以概括为:写放大优化策略短期内不会出现覆盖所有实现细节的强制统一标准,也不太可能有一条路线消灭所有其他路线。真正在发生的是接口层面的收敛和生态层面的分层解耦。标准化机构定义稳定的、可互操作的主机设备接口,如Deallocate、ZNS、FDP;厂商在接口之下继续自由竞争算法和固件;应用在上层自由选择最合适的接入方式。
这种“协议层统一、实现层差异、应用层适配”的结构,既保护了硬件创新空间,又降低了全行业的重复开发和迁移成本。对于业界来说,重点不再是争论“谁统一谁”,而是尽快把FDP、ZNS等新一代接口的软件生态做扎实,让写放大优化从少数大厂的定制能力,变成整个行业都可以享用的标准化红利。
17. 总结
写放大是NAND闪存物理约束与上层随机写假设之间冲突的产物,它无法被彻底消灭,只能被持续压缩。从FTL内部的冷热分离和精细化垃圾回收,到主机侧的TRIM提示,再到多流写、ZNS和FDP,整个行业的努力方向始终一致:让写入在空间上更集中、在时间上更有序、在信息上更透明。
回到“SSD写放大优化策略要统一标准了吗”这个问题,答案是分层的。在“失效通知”层面,TRIM/Deallocate已经统一并普及;在“顺序化与介质亲和”层面,ZNS已经形成标准并进入垂直场景;在“灵活数据放置”层面,FDP正在成为NVMe生态中主机协同的新基准,但生态成熟仍需时间。真正统一的是一个不断收敛的接口框架,而不是某一种排他性的技术路线。
对于工程师而言,眼下最有价值的做法是:先测清楚自己系统的WAF,确保TRIM链路畅通,基于负载选择合适的盘型和OP,然后根据技术栈的成熟度逐步尝试FDP或ZNS。对于产业而言,最值得期待的不是一个包罗万象的万能标准,而是主机、设备、文件系统和数据库围绕数据放置语义形成高效、开放、可互操作的协作生态。写放大的优化仍将继续,但它的未来形态已经清晰:主机更懂数据,设备更懂介质,标准让两者能够用同一种语言对话。