- 背景
ToplingDB,虽然 fork 自 RocksDB 并且兼容其 API,但实现了脱胎换骨的改进,最重要的就是实现了性能更高的 CSPP MemTable(Rep) 和 SST。
ToplingDB CSPP MemTable 设计精要 对 CSPP MemTable 进行了初步介绍。
关于共享内存shm和内存映射mmap的区别是什么? 介绍了 CSPP 直接将 MemTable 转化为 SST。
- 减小写放大
实际上,直接把 MemTable 转化为 SST,除了直接地减少 CPU/内存/IO 消耗,还可以带来进一步的收益:减小写放大。
LSM 的数据分为多层,通常情况下,每层数据规模是上一层的 10 倍(可配置),Level Compaction 对相邻两层 key 重叠的文件进行合并,由此带来写放大。
对于完全随机的输入,在系统进入稳定状态时,每层引入的写放大是 10,现实中的实际数据有一定规律,写放大远小于完全随机的数据,例如在 TPCC 测试中,通过 ToplingDB 的 WebView 可以看到:
这里写放大远小于随机数据在每层中引入的写放大(10),写放大的计算公式继承原版 RocksDB。
我们将 MemTable 尺寸设为 1G,max_bytes_for_level_base 也设为 1G,开启 convert_to_sst 时,L0 的写放大实际上是 0(图中显示的是 1.0) 。
与此同时,因为 max_bytes_for_level_base 比较大(默认是 256M),所以我们的 L1 尺寸实际上近似于 RocksDB 的 L2,由此,我们相当于消除了原版 L1->L2 的所有 Compact,假定原版 L1->L2 compact 写放大也是 3.7,我们这里相当于将总的写放大减小了 3.7。
再算上 L0 的实际写放大从 1.0 减到了 0,我们将总的写放大减小了 4.7!
- 为什么 ToplingDB 可以这样做
MemTable 转化成 SST 可以瞬间完成,max_write_buffer_number=2 就足以支撑最大的写压力。
CSPP MemTable 的内存是 File Mmap,从而,这些内存可以 swap 出去,特别是当存在不活跃的 SuperVersion 导致老旧 MemTable 无法释放时(没有访问,但也无法释放),malloc 的内存一般很少被 swap,就要一直占用物理内存。
所以,同样是 5 个(或者10个,20个)MemTable 无法释放,ToplingDB 只有活跃的 MemTable 占用物理内存,而 rocksdb 的所有 MemTable 都要占用物理内存。
其次,从 MemTable 转化来的 SST,和 MemTable 共享同一份 PageCache,相当于并未消耗额外内存。
再次,从 MemTable 转化来的 SST 不需要 BlockCache,又一次减小了内存用量。
所有这些优势叠加,ToplingDB 可以游刃有余,不附带任何条件地,全方位地优于 RocksDB 。
【完】
【附】write_buffer_size 和 max_bytes_for_level_base = 256M 时(rocksdb 默认值)
【附】write_buffer_size 和 max_bytes_for_level_base = 2560M 时(rocksdb 默认值的 10 倍)
这两个对比充分地展示了不同配置下写放大的差异:9.0 vs 6.6,因为实际上 L0 的写放大是 0,所以真实的写放大是 8.0 vs 5.6。
其中,L4 开始启用压缩,写放大是按压缩后的尺寸计算的,按未压缩的尺寸算,需要乘以 3.3(L4 压缩到30.6%),按 256M 配置,153.8*3.3 = 505.9,综合写放大是 9.0 + (505.9/221.4) - 1 = 10.3。所以真实的对比是 9.3 vs 5.6!