论文精简翻译 Online Deduplication for Databases

论文精简翻译 Online Deduplication for Databases

第一次看论文看得懵懵懂懂,尤其是涉及到编码以及差量压缩算法的时候,一脸懵逼。第二次看,为了翻译,详细地查了相关算法资料,终于看懂了。为了防止忘记,写下每个段落的总结,以下是目录:

1. Introduction

传统的去重办法Deduplication (dedup),是其将数据分块,然后用哈希值来标记每个块,最后将相同标记的块去重。在有很多文件,且很少被修改的场景下,dedup 发挥了很好的性能。但是实际上,如果要对记录进行大量更新修改,这种方法就不适用了。

作者提出了一种在线的数据库去重方法,dbDedup。其最高能压缩数据库 37倍,再加上快压缩技术能达到61倍。传输记录时使用前向编码,储存记录时使用后向编码。以及一个 lossy write-back delta cache 来减少更新原始记录的开销。还有一个叫做 hop 编码的技术,来减少编码距离。最后介绍了如何自适应的关闭去重功能。

作者在 MongoDB 上实现了 dbDedup 来测试性能。如下图1所示:对于采用了dbDedup的数据库,压缩倍数达到了20-30倍,而传统方法远远不及dbDedup。

image-20211023102912475

2. BACKGROUND AND MOTIVATION

2.1 Why Dedup for Database Applications?

传统的压缩是基于块的。比如 MySQL 的 InnoDB 会将内存页压缩后放入磁盘。当取回内存后,会一直保持压缩,直到有相关的查询读取该页的内容。这样的压缩效率很低。

分析型 DBMSs(Analytical DBMSs) 使用更加激进的手段,如字典压缩,游程编码。由于对每列都压缩,因此能找到更多相似性,且支持直接对压缩数据进行查询,这是MySQL 无法支持的。但是由于对每个记录的属性都要压缩,大大减慢了速度,是无法支持在线的互联网应用的。

重复数据一般来自于两种情况:

第一种是因为应用程序本身需要保存多个版本的信息。比如维基百科,百度百科,以及构成了25%网页的 WordPress。但对于一般的数据库而言,只会保存对活跃事务有关的历史信息,不会保存所有。其次,一般应用会将不同版本的信息作为不同的数据记录保存,也就不能放在一个页中被块压缩。

另一种是应用不同记录之间的重复。比如引用功能。邮件回复时会带上历史记录,留言板上会引用别人的话,这些都是传统数据库无法处理的重复数据。

但是部分场景下重复数据并不多,比如 OLTP(online transactional processing)。这是 IBM 对它的定义:What is OLTP? | IBM,可以简单理解为金融交易。

OLTP (online transactional processing) enables the rapid, accurate data processing behind ATMs and online banking, cash registers and ecommerce, and scores of other services we interact with each day.

对于这些重复数据很少的场景,dbDedup 需要自动识别并关闭去重功能以减少系统开销。

2.2 Similarity-based Dedup vs. Exact Dedup

去重一般可以分为两类,完全相同数据去重以及相似度去重。

传统的完全匹配数据块的去重方式流程一般是这样的:一个文件/记录进来后,使用 Rabin-fingerprinting 分为多个块。每个块计算一个哈希值,然后比较是否相同哈希值以及出现过了。一般来说,这种方法对于文件的储存是有效的,但是对于数据库的一条记录来说,相同部分大概大小为10-100B,但是以一般KB级别的块大小的话,无法找到这部分细小的相同。而如果将块分的更小的话,额外开销增大反而又抵消了性能的优化。

如下图2所示,dbDedup 的字节级增量压缩能够识别更细粒度的重复数据,因此比基于块的重复数据删除提供更大的压缩比。

image-20211023160804242

2.3 Categorizing Dedup Systems

如果对于去重的数据来分类,可以分为主要储存和次要储存。次要储存指的是备份的数据,而主要储存则指的是主要的数据服务结点。

如下表1所示,dbDedup 是第一个运行在主要储存,且使用相似去重的数据库。注意表下行中间一列代表既使用了相同去重也使用了相似去重。

image-20211023164149070

3. dbDedup DESIGN

以下介绍了 dbDedup 的工作流程、编码技术、避免IO的技术和避免不必要去重的方法。

3.1 Deduplication Workflow

下图3显示了去重的工作流程,主要为以下关键的4步:

  1. 对新纪录提取特征值
  2. 在数据库中寻找一批候选的相似记录
  3. 从候选记录中挑选一个记录
  4. 在相似记录和新记录之间进行差量压缩

image-20211023170252584

3.1.1 Feature Extraction

对于每个新纪录,dbDedup 使用 Rabin Fingerprinting 算法来分块,然后对这些长度不一的块用 MurmurHash 计算一个哈希值,这个哈希值与 SHA-1 相比较弱。对这个哈希值只索引一个能代表它的子集。子集的选择使用了一致抽样(consistent sampling)的办法,这比随机抽样能提供更好的相似性特征。然后特征被排序后,选择前K个,这样如果两个记录有一个特征相同,则表示二者相似。

由于只索引了哈希值的子集,因此索引所占的内存仅为每条记录最多K个索引项。这使得 dbDedup 能索引更多块,细粒度也就能更小。其次 dbDedup 并不需要哈希值完全一样才进行压缩。因为使用了比 SHA-1 更轻量的算法 MurmurHash,这会导致出现更多哈希碰撞,进而将更多记录误报为相似,降低了压缩率。但是最后 dbDedup 执行的是差量压缩,并不认为相似即为相同,因此并不会影响正确性。

3.1.2 Index Lookup

查找特征用到了布谷鸟哈希(Cuckoo)。其与桶上挂链的查找复杂度不断增长不一样,可以达到 O(1) 的常数查找效率,下面简单介绍其思想:

当哈希冲突,也就是新来的 key 映射到了另一个 key 的位置时,新来的 key 会将旧 key 踢出,占领旧 key 的位置。这就像杜鹃(其中一种为布谷)一样,将自己卵产在别的鸟窝里面,然后把别的鸟蛋踢走。

被踢出的旧 key 用其他办法找一个新位置。这种方法有:

  1. 再加一个独立哈希表,旧 key 放到原来表的对应位置
  2. 用新的哈希函数,映射到新的位置

本论文采用了后者,多加哈希函数的方式

  • 对一条记录计算的 K 个特征:
    • 使用布谷鸟哈希算法,将特征映射到一条记录。
    • 在哈希查找表中,键大小为2B,是特征的校验和;值大小4B,是一个指针,指向数据库中某个记录。
      • 使用多个哈希算法:
        • 将特征映射到多个桶,遍历每个桶:
          • 如果特征和桶的校验相同,则将桶指向的记录加入到相似记录中。
          • 如果相似记录达到了查找上限,则结束搜索
          • 如果找到一个空桶,则插入键值对,结束搜索。
  • 综合 K 个特征得到的相似记录

3.1.3 Source Selection

对于一个记录,可能找到了一堆相似记录,那么就需要从中选一个做差量压缩。dbDedup 做法是,对每个相似记录,你有多少个特征与原纪录特征相同,你就有多少初试分数。然后如果相似记录在 cache 里面,则再加一定分数。最后选一个分数最高的出来。如果在 cache 里面就加分,可能会选出不是那么相似的记录,但是却可以节省 IO 开销。具体效果 5.4 节阐述。

3.1.4 Delta Compression

3.2 节具体讲编码技术,4.2 节具体讲压缩算法。

3.2 Encoding for Online Storage

差量压缩有个问题,就是读取可能需要经过多个差量的读取,最终才能读取到最旧的一版数据。一般数据库会本地不差量,网络传输时差量,或者本地很有限的储存用差量储存。

dbDedup 使用双向编码技术来减少本地和远程的仓库大小,同时使用 hop 编码来减少最坏情况下对差量的读取。

3.2.1 Two-way Encoding

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dkf4V35T-1635923593139)(…/…/…/AppData/Roaming/Typora/typora-user-images/image-20211101170734355.png)]

如图 4(a) 所示,传统的差量编码是前向编码。其以旧数据为基础,保存后续数据与前者的差量。如当记录按照 R0、R1、R2 的顺序插入时,保存最旧数据 R0,以及两个新数据的差量。这样最新记录需要一层一层向前寻找差量,直到寻找原始数据后,按照顺序加上差量恢复。
R 2 = R 0 + Δ 0 , 1 + Δ 1 , 2 R_2 = R_0 + \Delta_{0,1} + \Delta_{1,2} R2=R0+Δ0,1+Δ1,2
这样的前向编码,适用于两个数据库同步时,新数据库向旧数据库传输数据的差量,而不是全量数据,这样能节省网络开销。但是缺点是,读取最新数据时,需要按照压缩顺序读取大量差量。

后向编码则以最新数据为基础,保存旧数据的差量。如图 4(b) 所示,还是按照 R0、R1、R2 的顺序插入数据。当插入 R1 时,会计算 R0 与 R1 之间的差量,然后保存差量以及最新的数据 R1。R2插入时同理。这样当需要读取旧数据,如 R0时,先读取 10之间的差量,然后再读取 2,1 之间差量,最后读取到 R2 后,恢复 R0。

后向编码好处是能快速读取最新数据,然后带来两个缺点:

  1. 额外的写入:前向编码只需向数据库写入差量即可,而后向编码还需要写入最新数据。dbDedup 解决办法是,将这部分要写入的数据缓存,等系统有空的时候再写入。
  2. 以旧数据为基础的差量:如图 5 所示,如果 R2 不再以 R1 为基础,而是以 R0 为基础。对于前向编码,只需要将差量指向 R0 即可,此时只保存了一份基础数据 R0 和两个差量。而后向编码时,需要先恢复出 R0,然后计算 2,0 之间的差量,然后用最新的差量 2,0 替换旧差量 1,0。此时保存了两份基础数据 R1、R2,和一个差量 2,0。比前向编码多保存一个数据,导致压缩率降低。所幸这样的中途更改不会很多,只有5%左右,5.2 节会具体介绍。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iaw3jJ0T-1635923593140)(…/…/…/AppData/Roaming/Typora/typora-user-images/image-20211101172702324.png)]

此外,双向编码并不意味需要计算两次差量。dbDedup 只需计算一个差量,然后重编码为另一种差量即可。

3.2.2 Hop Encoding

Hop 即单脚跳的意思。为了解决后向编码最坏需要遍历 N 个差量的,有两种办法,如图 6 所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wo5c8v9f-1635923593141)(…/…/…/AppData/Roaming/Typora/typora-user-images/image-20211101180726977.png)]

一种叫版本跳跃(version jump)。即将若干个差量打包,作为一个版本。每个版本里面保存一个原始数据,版本中其他数据都以这个原始数据为基准保存差量。这样一条链便成为一个个块,每个块都有一个原始数据。这样会降低压缩率。

另一种叫单脚跳编码(Hop Encoding)。它在不同差量保存了多个指针,指向其他差量。如上图所示,棕色的叫做跳板(Hop base)。其思路与跳跃表(skip lists)类似,采用多级间接编码来加速解码过程,L 级上的间隔为 H L H^L HL

如图 6 所示,当 H = 4 H = 4 H=4 时,L1 级的所有差量,每 4 个会有一个指针。当 L1 积累到 4 2 = 16 4^2=16 42=16 时,增加一层 L2, 以及一个指针。

跳跃表示例

上图是一个示例跳跃表。查询从左上角开始。如果当前节点数字 < 右边数字,则往右找;如果大于,则往下找。

这样可以得到三种编码方式的比较表格,如下表 2 所示。可以看出,单脚跳编码与版本跳时间各种情况的复杂度都差不多,但是单脚跳只保存一份原始数据,因此压缩率更高。

image-20211101182230977

3.3 Caching for Delta-encoded Storage

链状的编码天生适合缓存部分关键数据。dbDedup 使用了两个缓存,一个源记录缓存( source record cache),一个有损的回写差量缓存(lossy write-back delta cache)。前者帮助节省编码时的读,后者减少后向编码时的写放大。

3.3.1 Source Record Cache

和其他差量编码的系统一样,dbDedup 在读取相似记录进行差量时,都会需要额外的读操作。

考虑到许多相似的记录是在同一时间插入的,那么可以利用时间的局部性,将最新插入的记录缓存。例如维基百科的词条,某个话题的讨论,邮件的沟通,都发生在一个小的时间段里。因此在缓存中找到一个相似记录的概率很大。其次更新操作大多数是以前者为基础逐步增加内容的,因此两条记录如果创建时间接近,那么就更有可能相似。

因此,我们这样实现缓存:如果新记录选择了一个缓存中的相似记录,则在缓存中替换这个相似记录;如果是跳板(hop base),则替换缓存中临近的跳板;如果在缓存中没有找到相似记录,则以 LRU(Least Recently Used)的形式替换一个最近没有使用的记录。

3.3.2 Lossy Write-back Delta Cache

后向编码在方便读取最新数据的同时,也带来了更多的写入开销。插入新纪录时,需要额外写入差量;如果插入的是跳板,那么还需要对临近跳板写入更多指针。这在写频繁的场景下会产生更多写操作,拖累系统速度。

然而这部分差量的写入是可以丢失的。差量如果不替换原来的数据,最多就是导致压缩率降低,但是旧数据却没有丢失。因此 dbDedup 采用一个有损的回写差量缓存来储存差量。当每个记录插入时,会保存其原本数据,而差量则放入缓存中。缓存中的差量,按照差量替换数据后能节省的空间大小,由大到小排序。当系统插入时,如果缓存满,则丢弃贡献最小的差量。如果系统空闲,则按照贡献从大到小的顺序将差量写入数据库。

3.4 Avoiding Unproductive Dedup Work

dbDedup 需要自动识别去重效益很少的环境,并自动禁用去重。它采用两种方式:

  1. 监控压缩率,当压缩率太小时禁用去重。
  2. 一个自适应的过滤器,将那些对压缩率贡献很少的小记录过滤。

3.4.1 Automatic Deduplication Governor

通常,多个数据库一起去重,远不如多个数据库自己去重。因此 dbDedup 将记录的索引按照数据库拆分,如果某个数据库在一定插入数量,比如 10 万条数据插入后,依然压缩率很低,比如小于 1.1,那么就关闭去重,删除去重索引。已经去重的数据保持不变,后续插入的数据不进行去重。且后续对这个数据库并不重启去重

3.4.2 Adaptive Size-based Filter

观察发现,数据库大多数的重复,来自于那些较大的记录。图 7 展示了不同数据库的记录分布。实线表示数据库中累加一定大小内所有记录后的数目总和,占所有记录数目中的比率。虚线表示将累加记录去重后的空间节省,在总体空间节省中的占比。可以看到,60% 以上的大记录贡献了 90-95% 的压缩空间。因此忽略大小 40% 以下的小数据,将会在去重时减少 40% 数据,但压缩率只丢失了 5-10%。

具体而言,dbDedup 采用自适应的大小限制来过滤小数据。一开始限制为0,所有数据都进行去重。然后每 1000 条数据插入后,根据 40% 的小数据大小来更新这个限制。

图7

4. IMPLEMENTATION

本节主要介绍 dbDedup 如何融入 DBMS 、去重框架以及差量压缩算法的具体实现。

4.1 DBMS Integration

如图 8 所示,我们使用一个简单的分布式设置。一个主要结点负责写请求,然后将更新的数据异步传输到次要节点。

图8

Insert:

记录首先保存在主节点的 oplog 里面,以时间戳 + 记录的形式保存。当 oplog 大于一定大小后,将会以前向编码的形式发送到次要节点同步。编码时,如果找到了一个相似记录,则会先从源记录缓存中寻找该相似记录,如果缓存没命中,则直接读取。找到相似记录后,送入编码器中生成双向编码。dbDedup 将新纪录插入到主数据库中,然后缓存后向编码后空闲时回写。然后将前向编码附加到主 oplog 中,同时发送到次要节点。

次要节点的 oplog syncer 接收到前项编码后,会送到重编码器(Re-encoder)中。重编码器在本地储存中寻找前项编码对应的基本记录,然后恢复最新记录,再生成后向编码。最后将新记录写入并缓存后向编码。

除此以外,dbDedup 对每个记录都保存了一个 reference count 来储存有多少记录是以自己为基础编码的。这意味着,如果储存一个新纪录,由于采用后向编码,新纪录的计数则为1,而相似记录的计数则不变。

Update:

如果对一个计数值为 0 的记录更新,也就是更新一个没有别的相似记录依赖的记录,那么直接更新就好。否则,dbDedup 将更新内容附在记录后面,只有计数减少为 0 时,再将所有附的更新内容和记录合并。

Delete:

如果删除计数值为 0 的记录,直接删除即可。否则,标记为删除,任何后续读到这个记录的请求都将返回空,直到计数值为 0 后再物理删除,然后将这个记录依赖的基础记录的计数值减一。

Read:

如果查询的记录没有编码,返回即可。如果编码了,则需要解码后返回。

Garbage Collection:

当解码时,在编码链上,如果发现有记录被标记为删除但是还没有删,则 dbDedup 创建一个其前后记录的差量,然后将记录的计数值减一。

4.2 Delta Compression

dbDedup 的差量压缩的算法与 xDelta 算法相似。xDelta 算法由两个步骤组成:

第一个步骤是编码阶段。首先将源记录分块,每块 16B 大小。对每块计算一个 Alder32 校验和,然后将校验和以及块的偏移量在内存中索引起来。

第二步是扫描。在目标记录上,使用同样大小的滑动窗口,一字节一字节的滑动扫描。如果窗口的 Alder32 校验和在索引中找到,则从这目标和源记录这两个块开始,寻找双向的 LCS( longest common sequence 最长公共序列),后续扫描将跳过相同部分。

扫描完成后,便可以用 COPY 描述相同部分,INSERT 描述不同部分,来编码目标记录。

如图 9 所示,dbDedup 的差量算法是一种修改过的 xDelta 版本。考虑到 xDelta 大部分时间都在构建索引和查找索引,因此dbDedup 做了一些改善。在第一步编码时,dbDedup 在源记录和目标记录中取样一部分位置,所取样的块的校验和的若干低位 bit 一样。这些取样位置称为锚(anchor),锚之间的间隔表示采样比率,并由最后需要保证相同的位的长度控制。第二步扫描时,只对那些在锚里面的窗口进行查找,避免了每个窗口都查一次。锚的间隔提供了一个在压缩率和压缩速度权衡,会在第 5 节具体介绍。

图9

如算法 1 所示,由于篇幅的原因,算法的部分优化没有放上来,比如:连续并重叠的 COPY 操作可以合并;短的 COPY 操作如果编码的代价大于空间的节省的话,由 INSERT 替代。

算法1

在用上述算法计算了前向编码后,dbDedup 又使用了算法 2 所述的重编码来生成后向编码。与其交换源记录和目标记录再跑一次算法 1 来生成后向编码,算法 2 则利用了算法 1 生成的 COPY 指令。它将 COPY 指令按照源记录的偏移量排序,然后在不匹配的区域用 INSERT 命令填充,这样便生成了后向编码。虽然不是最优的,但是速度极快,因为不涉及校验和的计算和索引。

算法2

解码就很直接。跟着 COPY,INSERT 两个指令恢复即可。

5. EVALUATION

接下来使用四个真实场景数据集来进行测试。测试环境使用一个主节点,一个次要节点,一个客户节点。每个结点配置为 4 核 CPU,8 GB RAM,100 GB HDD 磁盘。实验基于 MongoDB 的 WiredTiger 储存引擎,关闭了完整的日志功能以避免干扰。使用 dbDedup 和传统的块级压缩 trad-dedup 来进行对比。结果显示 dbDedup 有更好的压缩性能,同时只增加了微不足道的开销。

5.1 Workloads

我们使用了四种数据,涵盖以下场景:

  1. 维基百科的协同编辑
  2. Enron 的邮件服务
  3. Stack Overflow 和 Message Boards 的在线社区

每种数据按照时间戳排序并插入数据库,然后按照公开的读取数据来模拟读取。

Wikipedia:

采用 2001 年 1 月到 2014 年 8 月,维基百科英语语料库中每一篇文章的完整修订历史。我们通过基于文章 id 的随机抽样抽取了一个 20GB 的子集。每个版本都包含文章的新版本和参与编辑的用户的元数据。例如,用户名、时间戳、评论等。大多数重复数据来自于对页面的增量修订。我们插入前 10,000 个修订以初始化数据库。然后我们根据公开的维基百科的访问评率发出读写请求,其中读写比率是 99.9 到 0.1 ,且 99.7% 的读都是请求最新版本的 wiki 页面,其余的读则是针对特定版本的。

Enron:

安然(Enron)是一个在美国以天然气起家的能源公司,本论文采用了它的公共电子邮件数据集。数据来自大约 150 个用户,大部分是安然的高级管理人员。该语料库包含大约 500k 条消息,总计 1.5 GB 的数据。每条消息包含文本主体、邮箱名称、消息头(如时间戳和发送方/接收方 id )。重复数据主要来自于转发或回复邮件时,对先前消息内容的附带。我们尽可能快地将排序过的数据集插入 DBMS 中。在每次插入之后,我们向特定的电子邮件消息发出一个读请求,导致总的读/写比率为 1 比 1。这是基于这样一个假设,即每个用户都使用一个电子邮件客户端,该客户端在本地缓存所请求的消息,因此每条消息都对 DBMS 进行一次写入和读取。

Stack Exchange:

数据来自 Stack Exchange 的公共数据,其中包含用户帖子的完整历史记录和相关信息,如标签和投票。我们通过随机抽样抽取了 10GB 的子集。这个数据集中的大部分重复来自于用户修改他们自己的帖子和复制其他讨论线程的答案。我们按时间顺序将帖子作为新记录插入 DBMS 中。对于每一篇帖子,我们发出读请求的次数与它记录的阅读次数相同。总读写比率为 99.9 ~ 0.1%。

Message Boards:

数据来自 Message Boards 论坛,大小为 10GB,包含从公共 vBulletin-powered 留言板抓取的许多用户帖子,这些留言板涵盖了各种主题,如运动、汽车和动物。每个帖子包含论坛名、帖子ID、帖子ID、用户ID,以及帖子主体(包括来自其他帖子的引用)。这个数据集还包含每个主题的阅读次数,我们使用它来生成总体的读查询。重复数据主要来源于用户引用他人的评论。为了模仿用户在论坛中的行为,每插入一个帖子,我们发出一定数量的对当前主题的读请求,请求包含主题中的所有之前的帖子。在一个主题下每个帖子的读请求数是通过将主题的总阅读数除以它所包含的帖子数得到的。

5.2 Compression Ratio and Index Memory

我们使用 dbDedup、trad-dbdup 以及 MonGoDB 默认的块压缩算法 Snappy 进行对比。将数据尽可能快的插入数据库,然后测量数据库大小,网络上传输的数据量以及索引的内存开销。

图 10 展示采用不同块大小的数据库的压缩率以及对应内存消耗。其中压缩率定义为原始数据大小除以压缩后数据大小。内存开销中不包括 32MB 的源记录缓存以及 8MB 的有损回写缓存。前者在 dbDedup 和 trad-dedup 都使用了,后者只在 dbDedup 中使用。

图10

这里整理了论文中用文字描述的所有的精确数据,空着的是论文没说的数据。后续论述不再文字中插入具体数据局
| 数据集 | 配置 | 压缩率(倍数) | 加上 Snappy 后的压缩率(倍数) | 内存开销(MB) |
| -------------- | --------------------- | -------------- | ------------------------------ | -------------- |
| Wikipedia | dbDedup 1KB 块大小 | 26 | 41 | 36 |
| Wikipedia | dbDedup 64B 块大小 | 37 | 61 | 45 |
| Wikipedia | trad-dedup 4KB 块大小 | 2.3 | 3.7 | 80 |
| Wikipedia | trad-dedup 64B 块大小 | 15 | 24 | 780 |
| Wikipedia | snappy | 1.6 | | |
| Enron | dbDedup 64B 块大小 | 3.0 | 5.8 | |
| Stack Exchange | dbDedup 64B 块大小 | 1.8 | 3.5 | |
| Message Boards | dbDedup 64B 块大小 | 1.3 | 3 | |

可以看到,压缩率最高的是维基百科。对于 dbDedup 而言,减小块大小会使得压缩率提高,但是同时内存却增加不大,这是因为它对每个记录只索引最多 K 个特征。反观 trad-dedup,块大小变小后,块数量增多,由于它需要对更多块索引,因此内存消耗陡然增大。此外还有一个原因是 trad-dedup 使用了更大的索引键,即 20 字节的 SHA-1 哈希值,对比而言 dbDedup 使用的则是 2 字节的校验和。此外 Snappy 的压缩率不高,只有 1.6 倍,且对于去重前数据和去重后数据都是 1.6 倍。因为没有索引也就没有内存开销,此外由于它并没有在应用级别之间的记录进行压缩,也就没有达到理想的压缩率。

对于其他数据集来说,压缩率并没有那么高,但都展示出 dbDedup 的优势,即压缩率高的同时内存开销小。对于 Enron 数据集来说,dbDedup 达到的压缩率与与我们从 Microsoft Exchange服务器的云部署上得到的实验结果一致。这个服务器包含了真实的用户电子邮件数据,且大小达到了 PB 数量级。另外两个论坛数据集的压缩率没那么高,这是因为用户并不像维基百科和邮件一样,经常引用或者修改评论。因为只能爬取到 Message Board 的最新数据,没有对帖子的修改数据,因此压缩率是保守的。

图 11 展示了 dbDedup 在本地储存和网络传输数据的压缩率的比较。可以看到本地储存压缩率稍低,这可能是因为 3.2 节中介绍的重叠编码以及回写缓存满时对部分差量的剔除。但二者查边保持在 5% 以内,这是因为重叠编码不太常见,且回写缓存每次只将压缩率低的差量剔除。

图11

5.3 Runtime Performance Impact

现在测量 dbDedup 对 DBMS 性能的影响。我们比较了 MongoDB 的三种部署配置:

  1. No compression(“Original”)
  2. dbDedup
  3. Snappy

对于每个设置,我们针对所有工作负载运行三次实验,并取平均值。

Throughput:

图 12a 显示了四种工作负载的吞吐量。可以看到大部分环境来说,dbDedup 和 Snappy 都没有造成吞吐量的降低。只有维基百科负载中,Snappy 降低了 5% 的吞吐量。这是因为一些大的维基百科记录不能放在一个 WiredTiger 页中,因此需要额外的 IO。

Latency:

图 12b 展示了客户端延迟的 CDF(Cumulative Distribution Function 累积分布函数)。这里只展示了 dbDedup 开启和关闭的比较。我们可以发现,启用 dbDedup 后的延迟分布曲线与未启用的分布曲线相似,也就意味着 dbDedup 在性能生几乎没有影响。区别是对于所有负载,99.9% 的延迟只慢了 1%。

图12

5.4 Effects of Caching

dbDedup使用两个专门的缓存来最小化读取和更新源记录的 I/O 开销:一个 32MB 的源记录缓存和一个 8MB 的有损回写缓存。现在我们评估这些缓存的有效性。

Source Record Cache:

图 13a 表示源记录缓存。它的左侧 y 轴表示规范化后的压缩比,右 y 轴表示缓存未命中率,也就是需要需要从储存中读取记录的占比。横轴的 Reward Score 表示在选择相似记录时,对在缓存中的记录给予的奖励分。

当不使用缓存时,每次对源记录的检索都会引起读查询。在使用缓存,但不优先选择缓存记录时(cache-aware selection),也就是对缓存中记录奖励 0 分时,缓存也可以消除 74% 的查询。在奖励分数为默认的 2 时,优先选择缓存进一步减少了40%的未命中率,降低到16%,且没有显著降低压缩比。进一步增加奖励分数会略微降低缓存缺失率,同时略微降低压缩率,因为不太相似但在缓存中的候选记录更有可能被选为源记录。

图13

Lossy Write-back Cache:

dbDedup 使用后向编码来避免读取最新版本时的连续解码。因此,去重一个新记录既包括写入完整的新记录,也包括用差量编码的数据替换源记录。替换时额外的写可能会导致 I/O 密集型工作负载在写突发期间出现严重的性能问题。dbDedup 的有损耗的回写缓存缓解了这些问题。

为了模拟具有密集 I/O 和空闲时间的突发工作负载,我们全速插入 Wikipedia 数据 10 秒,然后休眠 10 秒。图 13b 显示了MongoDB 在有回写缓存和没有回写缓存时的插入吞吐量随时间的变化。在没有缓存的情况下,由于额外的数据库写操作,DBMS吞吐量在繁忙时期明显下降。相反,使用回写缓存避免了 DBMS 在工作负载突发时的减速。

除了上面讨论的那些参数,dbDedup 还有两个主要的可调参数,它们是压缩和性能上的权衡:跳距(hop distance)和锚点间隔(anchor interval)。

5.5 Hop Encoding

dbDedup 使用 Hop 编码来避免最坏情况下对差量的查询。为了评估其有效性,我们同样在 MongoDB 中实现了版本跳转,并对两种编码方案进行了比较。

图 14 显示了随着跳距变化,另外三个指标的变化:与完全后向编码相比的压缩比、对于编码链长度为200的最坏情况源检索次数和回写次数。版本跳转会显著(60% 90%)降低压缩比,因为所有参考版本(reference versions)都是未经编码存储的。它的压缩比随着跳距的增加而提高,因为以未编码形式存储的记录更少。而对于 Hop 编码而言,由于跳板(Hop base)被存储为差量,它提供的压缩只比完全向后编码低 10%。其次,Hop 编码的压缩比随着单跳(Hop distance)距离的增加而保持相对稳定,这是由于跳板较少。

图14

Hop 编码的最坏情况源检索数与版本跳转的最坏情况源检索数相近。因为拥有若干跳级别(hop leverl),回溯到最近的跳板只需要对数时间。随着跳距的增加,解码时间由遍历相邻跳板之间的距离决定。

对于额外回写数量,当跳距较小时,hop 编码会带来更多回写,但对于两种方案而言,跳距的增加都会导致回写次数快速接近编码链的长度。根据经验,我们发现将跳距设为默认的 16 可以在压缩比和解码开销之间进行很好的权衡。

5.6 Optimization of Delta Compression

dbDedup 的性能优于 xDelta 算法,因为它减少了在插入记录时索引和查找的开销。它引入了一个可调的锚间隔来控制源字节流中采样率。

图 15 显示了 Wikipedia 工作负载中,不同锚点间隔带来的压缩比(左y轴)和吞吐量(右y轴)。当锚点间隔为xDelta的默认窗口大小 16 时,dbDedup 的效果几乎与 xDelta 相同。dbDedup 的增量压缩速度随着锚点间隔的增加而提高,因为它减少了在源记录索引中插入和查找的次数。压缩率并没有很明显的降低,因为 dbDedup 从匹配的点双向进行字节级比较。当锚点间隔为64时,dbDedup 的压缩吞吐量比 xDelta 高出80%,而压缩比仅损失 7%。将锚距增加到 128 可以进一步提高 10% 的吞吐量,但会导致 15% 的压缩比损失。因此,为了合理的平衡压缩比和吞吐量,我们使用 64 作为锚距的默认值。

图15

6. ADDITIONAL RELATED WORK

Database Compression:

在过去的几十年中,涌现了许多数据库压缩方案。大多数可操作的 DBMS 使用页级或块级压缩数据库内容。有些使用前缀压缩,它在每个页的所有行中查找给定列字段值开头的公共序列。就像我们的 dbDedup 方法一样,这种压缩要求DBMS 在处理查询之前解压缩元组。

在一些 OLAP 系统中,有一些方案允许 DBMS 以压缩格式处理数据。例如,字典压缩用短的固定长度的整数编码来替换重复出现的长域值(domain values)。这种方法通常用于面向列的数据存储。这些系统通常关注具有相对较小域大小的属性,并探索值频率的倾斜( explore the skew in value frequencies ),以将结果字典限制为可管理的大小。[56]中的作者提出了一种增量编码方案,其中排序列中的每个值都用前一个值的增量表示。尽管这种方法可以很好地处理数值,但不适用于字符串。

所有以上技术都没有检测和消除粒度小于单个字段的冗余数据,因此,对于许多固有地包含这种冗余的应用程序来说,便没有利用潜在的压缩改进。相比之下,dbDedup 能够通过字节级差量压缩来删除更细粒的冗余。与其他内联压缩方案不同,dbDedup 不在关键写路径中查询,因此,它对 DBMS 的运行时性能的影响很小。此外,由于 dbDedup 在记录级别压缩数据,所以它只执行一次 dedup 步骤,并将编码结果用于数据库存储和网络传输。相反,对于页面压缩方案,相同的记录将被压缩两次(在数据库页和 oplog 批处理中),以实现两层的数据缩减。

Delta Encoding:

在 差量编码技术上,曾经有大量工作,包括几种基于 Lempel-Ziv 方法的通用算法,例如 vcdiff、xDelta 以及 zdelta。对于特定的数据格式(如XML),可以使用专门的方案来提高压缩质量[28,63,39,52]。dbDedup 中使用的增量压缩算法改良自 xDelta,其关系已在第 4.2 节中讨论。

差量压缩用于减少文件传输和同步协议的网络流量。大多数系统假设相同文件的以前版本被应用程序显式地识别,并且重复只存在于相同文件的以前版本之间[61,557]。其中一个例外的是 TAPER [38],它通过发送差量编码的文件来减少同步文件系统副本的网络传输;它通过计算由文件块散列生成的 Bloom 过滤器上的匹配位数来标识相似的文件。dbDedup 在没有应用程序指导的情况下从数据语料库中识别出类似的记录,因此它是一种比大多数以前的系统更通用的方法。

dbDedup 中使用的后向编码技术是受到版本化存储系统(如RCS[59]和XDFS[42])的启发。类似的技术也被用于版本控制系统,如Git [41]和 SVN [29],以允许回溯提交历史。与这些系统显式地维护所有文件的版本沿袭不同,dbDedup 完全基于记录之间的相似关系建立编码链,因此不需要系统级的版本支持。[54]使用差量编码进行备份存储中的去重。它使用前向编码,并且只允许最大长度为两个条目的编码链。类似于其他使用版本跳转的差量编码存储系统,它必须牺牲压缩增益,以限制对基础数据的最坏情况检索。

据我们所知,dbDedup 是第一个为网络和存储级压缩探索不同编码形式的系统,并提供两者之间的有效转换。通过新的 hop 编码方案,dbDedup 显著地减轻了差量编码存储的压缩比和检索开销之间的痛苦权衡。此外,它还引入了新的缓存机制,专门用于差量编码存储,在最大限度提高内存效率的同时显著减少了所涉及的 I/O 开销。这些技术的结合使编码存储的在线访问成为可能。

Similarity Detection:

过去的工作已经提供了各种方法来计算草图(相似性度量)来识别相似的项目。Broder [24,25] 在网页环境中率先提出了识别对象特征,使相似对象具有相同特征的基本技术。几篇论文 [58,47,20,53,65] 提出了计算相似度检测草图的方法,这些方法对数据中的小编辑具有鲁棒性。dbDedup 使用的特征提取方法与 DOT [47]和 sDedup 相似[65]。

7. CONCLUSION

dbDedup 是一款轻量级的基于相似性的重复数据删除引擎,可以减少存储使用量和用于远程复制的数据传输量。结合部分索引和字节级差量压缩,dbDedup 实现了比块级压缩和块级去重更高的压缩比,同时内存开销不大。它使用新的编码和缓存机制来避免,访问差量编码所涉及的繁重I/O开销。在四个实际工作负载下的实验结果表明,dbDedup 能够在存储大小和复制流量方面减少 37 倍(结合块级压缩时减少61倍)数据,而对 DBMS 性能的影响可以忽略不计。

欢迎关注公众号,海涛的学习笔记。最新学习笔记都将在这里发布哦

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值