Titan 是由 PingCAP 研发的一个基于 RocksDB 的高性能单机 key-value 存储引擎,其主要设计灵感来源于 USENIX FAST 2016 上发表的一篇论文 WiscKey 。WiscKey
提出了一种高度基于 SSD 优化的设计,利用 SSD 高效的随机读写性能,通过将 value 分离出 LSM-tree
的方法来达到降低写放大的目的。
我们的基准测试结果显示,当 value 较大的时候,Titan 在写、更新和点读等场景下性能都优于 RocksDB。但是根据 RUM Conjecture,通常某些方面的提升往往是以牺牲其他方面为代价而取得的。Titan 便是以牺牲硬盘空间和范围查询的性能为代价,来取得更高的写性能。随着 SSD 价格的降低,我们认为这种取舍的意义会越来越明显。
设计目标
Titan 作为 TiKV 的一个子项目,首要的设计目标便是兼容 RocksDB。因为 TiKV 使用 RocksDB 作为其底层的存储引擎,而 TiKV 作为一个成熟项目已经拥有庞大的用户群体,所以我们需要考虑已有的用户也可以将已有的基于 RocksDB 的 TiKV 平滑地升级到基于 Titan 的 TiKV。
因此,我们总结了四点主要的设计目标:
- 支持将 value 从
LSM-tree
中分离出来单独存储,以降低写放大。 - 已有 RocksDB 实例可以平滑地升级到 Titan,这意味着升级过程不需要人工干预,并且不会影响线上服务。
- 100% 兼容目前 TiKV 所使用的所有 RocksDB 的特性。
- 尽量减少对 RocksDB 的侵入性改动,保证 Titan 更加容易升级到新版本的 RocksDB。
架构与实现
Titan 的基本架构如下图所示:
图 1:Titan 在 Flush 和 Compaction 的时候将 value 分离出
LSM-tree
,这样做的好处是写入流程可以和 RockDB 保持一致,减少对RocksDB
的侵入性改动。
Titan 的核心组件主要包括:BlobFile
、TitanTableBuilder
、Version
和 GC
,下面将逐一进行介绍。
BlobFile
BlobFile
是用来存放从 LSM-tree
中分离出来的 value 的文件,其格式如下图所示:
图 2:
BlobFile
主要由 blob record 、meta block、meta index block 和 footer 组成。其中每个 blob record 用于存放一个 key-value 对;meta block 支持可扩展性,可以用来存放和BlobFile
相关的一些属性等;meta index block 用于检索 meta block。
BlobFile
有几点值得关注的地方:
BlobFile
中的 key-value 是有序存放的,目的是在实现Iterator
的时候可以通过 prefetch 的方式提高顺序读取的性能。- 每个 blob record 都保留了 value 对应的 user key 的拷贝,这样做的目的是在进行 GC 的时候,可以通过查询 user key 是否更新来确定对应 value 是否已经过期,但同时也带来了一定的写放大。
BlobFile
支持 blob record 粒度的 compression,并且支持多种 compression algorithm,包括 Snappy、 LZ4和 Zstd等,目前 Titan 默认使用的 compression algorithm 是LZ4
。