当 NVMe SSD 的顺序带宽轻松突破 7 GB/s,而数据库系统的实际写入吞吐量却远未触达硬件上限时,问题往往不在硬件本身,而在数据库软件与存储介质的协作方式。传统数据库沿袭自磁盘时代的原地更新(in-place update)写入模式,在现代 NVMe 架构下会产生大量随机写入、触发 SSD 内部垃圾回收的写放大(write amplification)瀑布,严重削弱硬件性能并加速介质磨损。来自康奈尔大学的研究团队在 VLDB 2026 发表的论文《How to Write to SSDs》中,系统论证了采用异地更新(out-of-place write)策略对数据库系统充分利用 SSD 性能并延长其寿命的必要性,并提出了一套跨越 DBMS 层与 SSD 层的协同优化框架,涵盖 B-tree 重设计、写缓冲结构、批量提交与新型 SSD 接口适配等多个维度。
从原地更新到异地更新:写入范式转移的必然性
传统关系型数据库与多数键值存储的写入路径,本质上是将更新直接施加于数据所在位置 —— 定位目标页面、修改内容、写回原地址。这种原地更新模式在机械硬盘时代是合理选择,因为随机写入的磁头寻道代价极高,原地更新能天然保持数据局部性,降低读取时的寻道开销。然而在 NVMe SSD 环境下,存储介质不再受机械限制,随机写入与顺序写入的吞吐量差距大幅收窄,取而代之的是写入放大、垃圾回收(GC)和擦除周期(erase cycle)对性能和寿命的深层影响。
当数据库向 SSD 发送一条小范围更新时,SSD 控制器可能需要读取整个物理块(block)、修改其中相关页面、再将修改后的块写回新位置,同时更新闪存转换层(FTL)的逻辑地址到物理地址映射。若数据库频繁产生小粒度随机写入,SSD 内部的 GC 线程会被反复唤醒,搬运大量有效数据以腾出可用块,导致实际写入量是数据库逻辑写入量的数倍甚至十倍以上。论文中引用的数据表明,典型 OLTP 工作负载在传统原地更新模式下,闪存写入量可达逻辑写入量的 6–10 倍。
异地更新的核心思想是将更新操作从 “修改原位置” 转变为 “追加到新位置”。更新记录被写入一个独立的连续区域,原始数据位置保持不变,仅在元数据中标记该键已废弃或指向新版本。这样一来,数据库层的写入模式天然变成顺序追加,极大降低了对 SSD 内部 GC 的触发频率。同时,废弃的旧版本数据可以在后台合并过程中批量回收,而非逐条处理,摊销了垃圾回收的固定开销。
LeanStore 重设计:B-tree 的异地更新改造路径
研究团队选择 LeanStore 作为原型系统进行改造,原因是 LeanStore 是一款面向现代存储的内存键值存储引擎,采用原地更新的 B-tree 结构,与生产级数据库的存储引擎设计高度相似,具有代表性。改造的核心挑战在于:如何在保留 B-tree 查找效率的前提下,将更新路径从原地修改切换为异地追加,同时确保事务语义、崩溃恢复和并发控制不受影响。
改造方案包含三个关键设计点。首先,追加式 B-tree 节点更新:每个节点不再支持原地覆盖,而是在节点尾部追加新版本的记录条目(entry),每个条目携带序列号(sequence number)以区分新旧版本。查询时沿用 B-tree 的搜索路径,但在节点内执行线性扫描或二分查找时,优先选取序列号最大的有效条目。通过这种方式,范围查询的平均扫描代价仅增加常数因子,而写入路径从原来的读 - 修改 - 写三阶段简化为纯追加操作,消除了读放大。
其次,版本链式批量回收:系统中维护一个后台压缩线程,定期扫描各节点的版本链,将有效条目合并到节点头部,生成一个紧凑的新节点版本,同时批量释放废弃条目占据的空间。这个过程在数据库层完成控制,相比依赖 SSD 控制器做细粒度 GC,数据库层的合并策略可以感知工作负载局部性(例如优先回收冷数据节点),从而以更少的搬运次数实现更高的空间利用率。
第三,无锁并发与写缓冲分离:更新路径完全无锁 —— 写入线程仅将新条目追加到节点尾部,无需获取任何互斥锁或原子指令。读取路径则通过版本号检查(MVCC 风格的可见性判断)确保隔离性。写缓冲(write buffer)被设计为一个独立的结构,用于聚合来自多个事务的批量写入,只有当缓冲达到预设阈值(如 256 KB 或 4 ms 时间窗口)时才触发一次持久化落盘,将多个小写入合并为一次大顺序 I/O。
批量提交的协同优化:事务层与存储层联动
批量提交(batch commit)是减少事务提交开销和写入放大的经典技术,但在 NVMe 环境下,其优化空间远超传统认知。传统批量提交的优化目标是减少 fsync 系统调用次数,通过延迟提交将多个事务的日志合并为一轮持久化操作。而在异地更新架构下,批量提交需要与 LBA 排布策略深度协同,才能充分释放 NVMe 的并行带宽。
具体而言,事务提交时产生的日志记录和脏数据页面,在批量提交框架中被聚合成一个统一的写入批次。这个批次在落盘前会经过一次 LBA 重排(reordering)操作:将逻辑上连续的事务日志块和数据块,在物理上排列为连续的 LBA 区间。NVMe 驱动在接收这个批次后,可以将其合并为一次或少数几次大尺寸的 DMA 传输,触发 SSD 控制器的通道级并行写入,而非分散为多次小粒度命令队列操作。实验中,这种 LBA 亲和性排列(LBA affinity layout)使批量提交的尾延迟(p99)降低了约 40%,因为 SSD 控制器的内部队列调度避免了跨通道的数据碎片化。
批量提交与异地更新的协同还体现在崩溃恢复的一致性保证上。传统原地更新在崩溃后需要通过 REDO/UNDO 日志将数据页面恢复至一致状态,恢复时间随脏数据量线性增长。异地更新架构下,每次批量提交产生的写入本身即为幂等的追加操作 —— 崩溃恢复只需将追加的版本链截断至最后一次完整提交点即可,无需执行复杂的页面级回滚。研究团队的评估表明,在 15,000 warehouse 的 TPC-C 规模下,改造后的 LeanStore 崩溃恢复时间从原来的数十秒缩短至不足 3 秒。
性能收益与 SSD 寿命量化
论文给出了详尽的基准测试结果,覆盖 YCSB-A(读密集但有 50% 更新操作)和 TPC-C(高写入事务负载)两类典型工作负载。在 YCSB-A 场景下,异地更新的 LeanStore 相比原版原地更新版本,吞吐量提升 1.65–2.24 倍,而每操作触发的闪存写入量下降了 6.2–9.8 倍。这意味着在相同的 SSD 耐用期限(DWPD,Device DWPD)内,改造后的系统可以多处理 6–10 倍的事务量。
在 TPC-C 15,000 warehouse 的重载测试中,吞吐量提升达到 2.45 倍,闪存写入量减少 7.2 倍。考虑到 TPC-C 场景下事务的分布特点 —— 大量小事务分散在不同表和索引上 —— 异地更新的收益来源不仅是追加合并,还有后台压缩线程将同一时间窗口内多个事务修改的键集中到少数物理块,减少了 SSD FTL 的元数据更新量。
从 SSD 寿命维度量化:以一块典型的 3.84 TB NVMe SSD(耐写 1 DWPD,质保 5 年)为例,假设每日处理 1,000 万次 YCSB-A 操作,原版 LeanStore 每操作触发约 8 倍写放大,则每日净写入量约为 800 TB 写入量,已接近甚至超过质保上限。改造后的版本将写放大降至 1 倍以下,每日净写入量降至 100 TB 以内,SSD 在五年内的累计写入量完全处于安全范围内。
ZNS 与 FDP 接口适配:面向未来的存储协同
论文的一个重要延伸方向是对新型 SSD 接口的支持验证,包括 ZNS(Zoned Namespace SSD)和 FDP(Flexible Data Placement)。ZNS 将 SSD 内部空间划分为多个 Zones,每个 Zone 仅支持顺序追加和 Zone Reset,天然契合异地更新的写入模式。研究团队在论文的附加章节中展示了将 LeanStore 的异地更新架构映射到 ZNS Zones 上的设计思路 —— 每个 LSM-tree Level 或每个表的数据独占一个 Zone,后台压缩产生的合并写入直接追加到目标 Zone 的尾部,无需经历 FTL 的随机映射过程。
FDP 接口则提供了更细粒度的数据放置控制能力,允许主机端指定数据的预期寿命(lifetime)和放置策略(placement policy),SSD 控制器据此将冷热数据分流至不同类型的闪存块(如高耐久度的 SLC 区和高密度的 QLC 区)。改造后的 LeanStore 通过在元数据中标注键值的访问热度,将高频更新的热数据路由至耐久区,将批量导入且很少读取的冷数据直接写入高密度区,实现了存储介质的差异化利用。
这种 DBMS-SSD 协同设计的意义在于,它将存储介质的物理特性抽象为数据库层可直接操控的接口语义,使数据库设计者无需深入理解 NAND 闪存的块管理细节,也能利用 ZNS/FDP 的硬件能力优化性能和寿命。随着 ZNS 和 FDP 在企业级 NVMe SSD 中的逐步普及,这种协同设计将成为下一代存储引擎的标准实践。
工程实践中的关键参数配置
对于计划在生产系统中引入异地更新架构的工程团队,以下参数是需要重点调优的。第一是版本链回收阈值,通常以节点内废弃条目占比超过 50% 或版本链深度超过 3 为触发条件。过低的阈值会导致压缩线程过于频繁,消耗 CPU 和 I/O 资源;过高的阈值则导致空间浪费和版本扫描开销累积。第二是批量提交窗口大小,建议在 NVMe Gen4/5 环境下设置 64–256 KB 的批次容量和 1–4 ms 的时间窗口双阈值,以在延迟和吞吐量之间取得平衡。第三是写缓冲容量,需要结合数据库可用 DRAM 比例和目标工作负载的峰值写入速率确定,一般推荐预留 512 MB–2 GB 作为写缓冲,在缓冲即将满时触发强制持久化以避免反压(backpressure)。
此外,监控指标层面应增加闪存写入量与逻辑写入量的比值(即 SSD 层的实际写放大系数)、批量提交批次合并率、以及版本链平均深度,以便在运行时感知存储效率的变化趋势。研究团队在原型系统中集成了上述指标导出接口,发现这些指标的波动往往早于吞吐量的下降,是预测 SSD 剩余寿命的先行指标。
结语
《How to Write to SSDs》揭示的核心结论是:在 NVMe SSD 已成为主流存储介质的今天,数据库系统的写入路径设计必须进行一次范式转移 —— 从适应机械硬盘的原地上下文更新,转变为适配闪存介质的异地追加与批量合并。这不仅是存储引擎内部的实现改动,更涉及事务提交协议、崩溃恢复机制、LBA 排布策略与硬件接口适配等多个层面的协同设计。对于系统架构师和存储工程师而言,理解并实践这一协同设计理念,是在 NVMe 带宽墙下真正释放硬件潜力、延长 SSD 服务寿命的关键路径。
资料来源
- Bohyun Lee, Tobias Ziegler, Viktor Leis. "How to Write to SSDs." Proceedings of the VLDB Endowment, Vol. 17, 2026. arXiv:2603.09927.
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。