rocksdb-doc-cn

关于压缩(Compaction)与压缩(Compression)的区别

这段内容在原文是没有的,翻译君实在没有什么好办法,不得不加上这段话

RocksDB涉及两个压缩概念,英文原文是Compaction和Compression。两个术语用中文翻译,都是“压缩”,实际上大家交流的时候也都是使用“压缩”。这个wiki很良心地写了两个压缩的内容,用英语能区分,但是用中文。。。嗯。。。。这里简单介绍下两个压缩的区别。

compaction,在RocksDB,或者说LSM存储中,指的是把数据从Ln层,存储到Ln+1层这个过程,例如把重复的旧的数据删除之类的。

compression,在这里指的是数据压缩,把1MB的数据压缩成500KB这样。数据还是那些数据,只是从明文,变成了压缩之后的数据。

他们的关系大概是:

通过Compaction把数据压缩到不同的层,每层使用不同的Compression算法压缩数据,减少存储空间。

下面开始是正文。

压缩算法限制LSM树的形状。他们决定了那些排序结果可以被合并以及那些排序结果需要被一个读取操作访问。你可以参考多线程压缩了解关于RocksDB压缩的更多细节。

压缩算法概述

源:https://smalldatum.blogspot.com/2018/08/name-that-compaction-algorithm.html

这里我们展示一系列压缩算法:经典Leveled,Tiered,Tiered+Leveled,Leveled-N,FIFO。除了这些,RocksDB实现了Tiered+Leveled和termed Level,Tiered termed Universal,FIFO。

经典Leveled

经典Leveled压缩算法,第一次在O’Neil et al的LSM-tree论文中出现,将读操作的空间放大以及写放大最小化。

LSM树是一系列的层。每一层都是一个排序结果,可以被按照范围切分成许多分片放到独立的文件中。每一层都比上一层大非常多倍。相邻层的大小倍数叫做扇出,当所有层之间的扇出都相同的时候,写放大会被最小化。把数据压缩进第N层(Ln)会把地N-1层(Ln-1)的数据合并到Ln。压缩到Ln会把之前和并进Ln的数据重写。最坏情况下,每层的写放大等于扇出数,但实际操作中,通常他会比扇出数小,Hyeontaek Lim et al的论文有相关解释。

原始LSM论文中的压缩算法使用 all-to-all的——所有Ln-1的数据会跟所有Ln层的数据合并。LevelDB和RocksDB的则是some-to-some的——Ln-1的部分数据和并进Ln层的部分数据(有覆盖的部分)

尽管leveled的写放大通常比tiered要大,但是在某些场景,leveled是有优势的。首先是按key顺序插入,一个RocksDB的优化大大减少这种场景的写放大。另一个是有倾向性的写操作,导致只有一小块的key会被更新。把RocksDB的压缩优先级设置为正确的数值,压缩过程应该在层数最小的,拥有足够空间存储写操作的层停止——他不会一致写到最大层。当leveled压缩是some-to-some模式,那么压缩只会对LSM树的一个写操作覆盖了的分片进行处理,这样可以让写放大比all-to-all模式小很多。

Leveled-N

Leveled-N跟Leveled压缩算法很像,但是会有更小的写放大,更多的读放大。它允许每层拥有大于一个排序结果。压缩合并所有Ln-1的排序结果到Ln的一个排序结果中,也就是Leveled。然后”-N“会被驾到名称中用于暗示每层可能会有n个排序结果。Dostoevsky的论文定义了一个压缩算法,名称是Fluid LSM,他最大的层有一个排序结果,但是非最大层有多于一个排序结果。leveled压缩会在最大层完成

Tiered

Tiered压缩通过增加读放大和空间放大,来最小化写放大。

LSM树仍旧可以看成是Niv Dayan和Stratos Idreos论文中讲到的一系列的层。每一层有N个排序结果。每个Ln层的排序结果都比上一层的排序结果大n倍。压缩合并同一层的所有排序结果来构造一个下一层的新的排序结果。这里的N与leveled压缩的扇出类似。合并到下一层的时候,压缩不会读/重写已经排序好的Ln层的结果。每层的写放大是1,远小于Leveled的扇出。

一个比较接近Tiered的实现是合并相似大小的排序结果,不必关心层的概念(这个概念会引入一个特定大小的排序结果的目标数字)。大多数(实现)包含一些主压缩的概念,也就是包含最大的排序结果,然后还有一些条件用来触发主,和非主压缩。通常的情况是会导致大量的文件以及自己。

tiered压缩也有一些挑战:

对于tiered压缩,层的概念通常是一个用于构成LSM树形状的概念,以及用于估算写放大。对于RocksDB而言,他们还是一个开发细节。L0之上的层在LSM树中可以用来存储更大的排序结果。这样做的好处是可以吧排序结果切分成更小的SST文件。这减少了最大的bloom过滤器以及块索引块的大小——这对于块索引更友好——并且在分片索引/过滤倍支持之前是一个非常重要的主意。如果引入子压缩,就可以使对大块排序结果进行多线程压缩变为可能。注意RocksDB使用“universal”而不是tiered这个名字。

Tiered压缩算法在RocksDB的代码里倍命名为“Universal压缩”。

Tiered+Leveled

Tiered+Leveled会有比leveled更小的写放大,以及比teired更小的空间放大。

Tiered+Leveled实现方式是一种混合实现,在小的层使用tiered,在大的层使用leveld。具体哪一层切换tiered和leveled可以非常灵活。现在我假定如果Ln是leveled那么所有之后的层(Ln+1,Ln+2)都是leveled。

VLDB2018的SlimDB是一个tiered+leveled的例子,机关它允许Lk层使用tiered,Ln使用leveled,而k>n。Fluid LSM倍描述为tiered+leveled的实现,但是我认为它是Leveled-N。

RocksDB中的Leveled压缩也是Tiered+Leveled。遵照max_write_buffer_number的设置,可能会有N个排序结果在memtable这一层——只有一个是活跃可写的,剩下的都是只读,等待落盘的。一个memtable落盘过程类似于tiered压缩——memtable的输出在L0构建一个新的排序结果并且不需要读/重写L0上已经存在的排序结果。根据level0_file_num_compaction_trigger的配置,L0可以有多个排序结果。所以L0是Teired的。memtable层没有压缩,所以也就没有该层是tiered还是leveled的说法。RocksDB中L0的子压缩过程会更加有趣,但这是另一篇文章的内容了。

FIFO

FIFO 风格的压缩在淘汰的时候把最老的文件丢弃,可以被用于缓存数据。

选项

这里我们给出选项的概述以及他们如何影响压缩:

其他会影响压缩性能以及触发条件的选项是:

压缩还可以人工触发,参考 人工触发压缩

参考rocksdb/options.h了解更多的选项信息。

Leveled风格压缩

参考Leveled-Compaction

Universal风格压缩

关于Universal风格的压缩的描述,参考Universal-Compaction-Style

如果你正在使用Universal风格的压缩,有一个CompactionOptionsUniversal对象,会持有该风格的所有特殊压缩配置。额外的定义在rocksdb/universal_compaction.h,你可以在Options::compaction_options_universal中设置他。我们在这里简单介绍Options::compaction_options_universal:

FIFO压缩风格

参考 FIFO压缩风格

线程池

压缩过程在线程池中进行,参考线程池

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账