本节摘要:RocksDB 不是 LevelDB 的「增强版」这么轻巧——它是对一个理想模型在四个具体失灵点上的系统性重造。本节从 Facebook 2012 年的写放大困局讲起,复盘 LevelDB 单线程压缩、无统计钩子、全硬编码三大缺陷如何逼出一个工业级引擎,再沿三次跃迁梳理十余年的演进脉络,最后给出 LevelDB、RocksDB、WiredTiger、Badger 的对比表与选型判断。
先摆一个真实的排查场景。2012 年前后,Facebook 的社交图谱服务 TAO 跑在传统存储之上,用户关系数据量涨得比缓存扩容快。工程团队的工单里反复出现同一组症状:写入延迟在每天的峰值时段规律性恶化;SSD 的磨损消耗远超容量规划模型;从库同步延迟长期压不下去。逐层排查后,锅落在了底层键值引擎身上——当时他们试用的是 Google 2011 年开源的 LevelDB。
这个结果让很多人意外。LevelDB 出自 Jeff Dean 与 Sanjay Ghemawat 之手,核心实现只有一万行上下的 C++:内存里一个跳表 MemTable,磁盘上分层的 SST 文件,后台 Compaction 负责归并与淘汰。代码干净、语义完备、极易验证,是教科书级的 LSM 实现。问题在于,教科书不处理凌晨三点的告警。工程团队逐项核对后列出了一张失灵清单,这四条清单后来几乎逐字变成了 RocksDB 的需求文档:
注意这四条的共性:没有一条是「算法不先进」,全部是「不可控、不可观测、不可替换」。LevelDB 为可验证的正确性而生,而生产环境需要的是可调控的可靠性。这个分野决定了后来 RocksDB 的全部性格。
2012 年底,Dhruba Borthakut 牵头的团队以 LevelDB 为起点开工,2013 年 RocksDB 正式开源。十余年下来,它的演进可以切成三段,每一段都在补上一段留下的账。
这一阶段解决的是上面清单里的第 1 和第 4 条。两件标志性的事:一是引入 Column Family(列族),让一个实例内部可以划出多个独立的逻辑域,每个域有自己的 MemTable、层级与压缩策略——隔离的问题从此有了官方答案;二是把 Compaction 拆成可调度、可观测、可中断的阶段,后台任务从「一旦开始必须做完」的黑盒,变成可以参与资源博弈的一等公民。多线程 Compaction 与细粒度统计也在这一时期补齐。这一阶段的标志性成果,是 RocksDB 成为 MySQL 存储引擎 MyRocks 的底座——一个嵌入式引擎第一次证明自己扛得住 OLTP 级别的事务负载。
引擎稳了,硬件环境却开始变得五花八门:NVMe、大内存、对象存储、混合介质。RocksDB 的应对是把「介质差异」翻译成配置项。BlobDB 把大 Value 从 SST 里剥离出去单独存放,SST 里只留句柄,缓解大值场景下 SST 的膨胀与频繁重写;TTL 过滤器让过期数据在 Compaction 时自动清退,时序场景从此不用自己写清理任务;WAL 与数据文件可以分开指定介质,日志上低延迟盘、数据走高吞吐盘。这一阶段的关键词是「接受不均匀」:引擎不再假设一块均匀的磁盘,而是接受由不同介质拼成的存储拓扑,并让数据生命周期与介质特性绑定。
规模问题解决后,新问题变成「配置组合爆炸」:两百余个配置项,普通团队根本无从下手。近年的演进集中在让引擎自己参与算账——更细的统计与追踪接口、按负载动态调整的触发逻辑、以及对 ZNS 分区介质这类新硬件的原生适配。社区里关于自动调参、学习型压缩策略的讨论从未停止。要强调的是,这一跃迁远未完成,生产环境的主流仍是「人工设定参数、指标验证效果」,这也是本教程第 8 章花整整一章讲调优方法论的原因:在引擎学会自己记账之前,账还得人来算。
下面这张图把十余年的关键节点放在一条线上,方便对照每笔「欠账」与「还账」的先后。

出处讲完,直接回答一个工程问题:什么时候选 RocksDB,什么时候不选。下面把四个常被放在一起比较的引擎按统一口径过一遍。InnoDB 是 B+ 树阵营的代表,放进来是为了看清「LSM 与 B+ 树」这条最大的分界线。
| 维度 | LevelDB | RocksDB | WiredTiger(MongoDB) | InnoDB(MySQL) | Badger(Go) |
|---|---|---|---|---|---|
| 核心结构 | 单一 LSM | 多列族 LSM | B+ 树为主、日志混 LSM | B+ 树 | LSM 加独立值日志 |
| 写放大 | 高且不可控 | 可调,逐层可控 | 较低,日志有额外开销 | 中,随机写页 | 低,值不重写 |
| 读放大 | L0 堆积时陡增 | 布隆加多层索引压制 | 稳定,树查找 | 稳定,树查找 | 需两次查找 |
| 空间放大 | 无预算概念 | 可预算可监控 | 中 | 中,碎片与页空洞 | 依赖值日志回收 |
| 可观测性 | 几乎为零 | 数百项指标 | 关键路径统计 | 较完善 | 基础统计 |
| 适用场景 | 学习与原型 | 写密集、大吞吐、嵌入式底座 | 文档型混合负载 | 读密集事务 | Go 生态、写密集轻场景 |
这张表的用法比结论重要:先问自己的负载在哪一列敏感。写入吞吐压倒一切、读取可以容忍多层查找——LSM 阵营;点读延迟与复杂查询压倒一切、写入量温和——B+ 树阵营;两边都要——要么接受 RocksDB 加多层缓存的组合拳,要么重新审视需求。几个被广泛验证的选型结论:写占比高、数据量上 TB 的场景,RocksDB 对 InnoDB 常有数倍的写入吞吐优势,这就是 MyRocks 能在用户资料库场景大规模落地的原因;而重事务、重 JOIN 的场景,InnoDB 的成熟度仍然难以替代。
用一个小实验建立体感。在同一台机器上分别用 LevelDB 与 RocksDB 各跑一轮持续随机写入,打开 RocksDB 的统计后你会看到两个引擎「物理写入字节」与「逻辑写入字节」的比值差异:LevelDB 的数字不受你控制,RocksDB 的数字随参数平滑变化。这一步不需要写代码,两侧都提供现成的基准工具。当你在第 5 章看到写放大的正式定义时,回过头看这组数字,会理解得比只读定义深一层。
下一节把全书通用的词汇表一次立起来:LSM-Tree 的三句话纲领,以及 MemTable、SSTable、序列号这些将伴随你读完本书的概念。