https://mp.weixin.qq.com/s/qMQqTzFsvKgyqhGpmjJ0Qw
传统的 SQL 和 NoSQL 数据库通常使用其自己的专有存储引擎来构建。MySQL 使用 InnoDB,Postgres 带有内部 B树,哈希和堆存储系统,Cassandra 带有 LSM树的实现。最近,其中一些数据库添加了 RocksDB 的后端(例如 MyRocks 和Rocksandra)。从长远角度去看,这让人感觉 RocksDB 正在吞噬低级存储的生态系统。但是经过仔细检查后发现,这些现有系统的 RocksDB 后端存在重大问题。
当构建任何复杂的软件时,不可能从头开始构建每个组件。重用现有组件可以缩短上市时间,而且通常是更好的产品,因为领域专家们花了很多时间来制作和调整各个组件的性能和耦合。使用 RocksDB 的这个选择当然是对的,但是随着时间的推移,计算发生了变化。许多不同的系统都使用 RocksDB。这种广泛的用途意味着要进行大量的测试和性能调整,但这也意味着 RocksDB 服务于许多主服务器。我们可以在 RocksDB 的非常庞大的功能集和配置表域中看到此效果。RocksDB 的代码库随着时间的推移而扩展,从 LevelDB 的原始3万行代码发展到目前的 350k+ 行代码状态。当然,只通过代码行来判断是一个不严谨的指标,但是这些数据确实提供了相对复杂性的粗略感觉。
RocksDB 为 CockroachDB 奠定了坚实的基础。不幸的是,随着 CockroachDB 的成熟,我们在 RocksDB 中遇到了严重的问题。例如,RocksDB 在与压缩有关的代码中存在一个错误,该错误导致对特定 sstable 进行无限次的压缩循环,从而使 LSM树 的其他部分无法进行压缩。虽然我们在 RocksDB 中遇到的 bug 的绝对数量是可以接受的,但它们的严重性通常很高,而修复它们的紧迫性通常是 House Is On Fire。这就使 Cockroach Labs 工程师深入研究 RocksDB 代码库,作为可以进行错误调查的一个基础要求。定位超过35万行外来 C++ 代码是可行的(我们已经做到了),但很难说这是一个好的解决方案。CockroachDB 主要是用 Go 编写的,而 Cockroach Labs 的工程师已经在 Go 的开发积累了广泛的专业知识。C++ 的专业知识很少,所以在 Go 和 C++ 之间心里上的障碍是真是存在的。这个障碍会阻止在本机 Go 配置文件工具的使用中进行内部检查 C++ 代码或进行 C++ 堆栈跟踪。为了避免频繁地从 Go 过渡到 C++ 的性能开销,有时我们不得不用 C++ 编写大量的 Go 中已经存在的逻辑。
RocksDB 通常具有很高的性能,但是我们也遇到了重大的性能问题。CockroachDB 是范围删除的早期采用者,但我们也是在早期实现中一些性能缺陷的早期发现者。我们在上游进行了针对范围删除的性能修复程序,并协助设计了v2实施方案。
RocksDB具有全功能,但有时这些功能存在缺陷。有时,我们选择解决 CockroachDB 代码中的这些缺陷,而不是在 RocksDB 中进行修复。但是这些决定不一定是有意识地做出的(有关 Go 和 C++ 之间的心理障碍,请参见上文)。这种解决方法的一个示例是 CockroachDB Compactor。压缩程序用于在 RocksDB 中强制压缩最近通过 DeleteRange 操作删除的部分数据。与不执行任何操作相比,这可以更快地恢复磁盘空间。对Compactor 的需求源于 RocksDB 在其压缩决策中未考虑范围删除操作。从底层细节更进一步,得出的结论是,存储引擎对 CockroachDB 的功能和行为具有至关重要的影响。拥有自研的存储层使 CockroachDB 可以更直接地控制自己的命运。
挑剔的读者可能会指出,以上几点并未得出重新实现 RocksDB 的结论。相反,我们本可以选择提升内部专业知识。我们本可以选择派生 RocksDB,剥离不需要的部分,并根据 CockroachDB 的需求进行增强。我们也对后一种方法进行了认真的考虑,但是最终我们拒绝在 Go 中重新实现 C++ 的逻辑,因为我们认为消除 Go / C ++ 障碍将使长期的更快开发成为可能。
最后的选择是使用另一个存储引擎,例如 Badger 或 BoltDB(如果我们想坚持使用Go)。出于多种原因,未认真考虑此替代方法。这些存储引擎并未提供我们所需的所有功能,因此我们需要对其进行重大增强。如果我们使用另一个存储引擎,运行RocksDB 的 CockroachDB 群集的迁移过程将变得更加复杂,这使得我们可能需要在相当长的时间内支持两个存储引擎。支持多个存储引擎本身就是一项巨大的工作:它显着增加了测试表的域,并且替代存储引擎通常会带来很多额外的问题(例如 MyRocks 不支持 SAVEPOINT)。最后,各种 RocksDB-ism 已渗入 CockroachDB 代码库,例如使用 sstable 格式在节点之间发送数据快照。删除这些 RocksDB-ism 或提供适配器,将是一项巨大的工程工作,或者会带来不可接受的性能开销。