RocksDB. Leveled Compaction原理分析
一 RocksDB的磁盘数据组织层次
1 磁盘文件的组织方式
rocksdb在磁盘上的文件是分为多层的,分别叫做level-0, level-1等等
level0上包含的文件,是由内存中的memtable dump到磁盘上生成的,单个文件内部按key有序,文件之间无序。
其它level上的多个文件都是按照key有序的。
2 data range partition
非0 level上的key,按序分片,保存在不同的文件中。
data range partition3 key在SST文件中查找
每个level的文件都是整体有序,并且文件内有序的。
要在某个level上查找某个key时:
- 先根据每个文件的start/end key对所有文件进行二分查找来确定哪些文件可能包含key
- 再通过二分查找在候选的文件中定位key的准确位置
这是一次对一个level上所有文件的二分查找的过程。
二 数据压缩 Compaction
1 L0 compaction
当L0的文件数量达到level0_file_num_compaction_trigger的值时,触发L0和L1的合并。通常必须将所有L0的文件合并到L1中,因为L0的文件的key是有交叠的(overlapping)。
L0与L1的compaction2 高层Compaction
当L0 compaction完成后,L1的文件总size或者文件数量可能会超过阈值,触发L1向L2的合并。从L1至少选择一个文件,合并到L2中key有交叠的文件中。
L1向L2合并同样的,合并后可能会触发下一各level的compaction。
合并后的L2 L2向L3合并合并后的L3也需要做Compaction.
合并后的L3
3 并行Compaction
并行compactionmax_background_compactions控制了并行compaction的最大数量。
4 L0 subcompaction
L0向L1的compaction不可以与其他level compaction并行。这可能成为整体compaction速度的瓶颈,可以通过设置max_subcompactions来加速L0到L1的compaction。
subcompaction5 Compaction的选择策略
当多个level都满足触发compaction的条件,rocksdb通过计算得分来选择先做哪一个level的compaction。
- 对于非0 level,score = 该level文件的总长度 / 阈值。已经正在做compaction的文件不计入总长度中。
- 对于L0,score = max{文件数量 / level0_file_num_compaction_trigger, L0文件总长度 / max_bytes_for_level_base} 并且 L0文件数量 > level0_file_num_compaction_trigger。
得分最高的level有限做compaction。
6 compaction触发阈值
每一层的compaction阈值设置策略由level_compaction_dynamic_level_bytes来决定。
当level_compaction_dynamic_level_bytes为false
L1 触发阈值:max_bytes_for_level_base
下面的level触发阈值通过公式计算:Target_Size(Ln+1) = Target_Size(Ln) * max_bytes_for_level_multiplier * max_bytes_for_level_multiplier_additional[n]. max_bytes_for_level_multiplier_additional
例如:
max_bytes_for_level_base = 16384
max_bytes_for_level_multiplier = 10
max_bytes_for_level_multiplier_additional = 1
那么每个level的触发阈值为 L1, L2, L3 and L4 分别为 16384, 163840, 1638400, and 16384000
当level_compaction_dynamic_level_bytes为true
最后一个level的文件长度总是固定的。
上面level触发阈值通过公式计算:Target_Size(Ln-1) = Target_Size(Ln) / max_bytes_for_level_multiplier
如果计算得到的值小于 max_bytes_for_level_base / max_bytes_for_level_multiplier, 那么该level将维持为空,L0做compaction时将直接merge到第一个有合法阈值的level上。
例如:
max_bytes_for_level_base = 1G
num_levels = 6
level 6 size = 276G
那么从L1到L6的触发阈值分别为:0, 0, 0.276G, 2.76G, 27.6G,276G。
这样分配,保证了稳定的LSM-tree结构。并且有90%的数据存储在最后一层,9%的数据保存在倒数第二层。
image.png参考资料:官方wiki