wisckey论文笔记

380 阅读26分钟

文章首发公众号: 小平杂记

目的

将键和值分开,以最小化I/O放大。WiscKey的设计是高度面向SSD优化的,利用了设备的顺序和随机性能特性

效果

我们通过微基准和YCSB工作负载展示了WiscKey的优势。微基准结果显示,WiscKey加载数据库的速度比LevelDB快2.5×-111×,随机查找快1.6×-14×。在所有六个YCSB工作负载中,WiscKey都比LevelDB和RocksDB快。

LSM介绍

磁盘索引结构

适合磁盘的索引结构通常有两种,一种是就地更新(B+Tree),一种是非就地更新(LSM)。

B+树

就地更新的索引结构拥有最好的读性能(随机读与顺序读),随机读是因为预读+缓冲的优化,性能也不差,B+树扫描是顺序读,读性能稳定(从根节点查询到叶子节点),而随机写性能很差(查询到叶子节点最后写磁盘是随机的,且涉及页分裂),无法满足现实工业中的工作负载要求,B+树适合读多写少的场景。

LSM树

LSM优势

LSM树的主要优势在于它们保持写入的顺序访问模式,基于LSM的技术的成功与其在经典硬盘驱动器(HDD)上的使用密切相关。在硬盘中,随机输入/输出比顺序输入/输出慢100倍以上,而B树上的小更新可能涉及许多随机写入,因此在固态存储设备或硬盘驱动器上都没有效率,LSM适合写多读少的场景。

LSM应用

基于LSM树构建的各种分布式和本地存储被广泛部署在大规模生产环境中,例如谷歌的BigTable和LevelDB、脸书的Cassandra、HBase和RocksDB等

LSM存在的问题

写和读放大是LevelDB等LSM树中的主要问题。写(读)放大被定义为写入(从)底层存储设备的数据量与用户请求的数据量之间的比率。存在读写放大,读放大是指访问一个key可能需要访问多次,最差情况是每一层都需要访问,写放大是merge过程中,一个kv item可能会被多次merge,每次merge都是读取然后写入磁盘 LSM 是以牺牲读取性能以及空间利用率为代价而换取顺序写入性能的。因此,对LSM结构的优化目标就是想办法提高读取性能和空间利用率。

写入放大

为了实现大部分是顺序的磁盘访问,LevelDB写入的数据比必要的多(尽管仍然是顺序的),即LevelDB具有很高的写入放大率。由于Li的大小限制是Li-1的10倍,当在压缩期间将一个文件从Li-1合并到Li时,LevelDB在最坏的情况下可能从Li读取多达10个文件,并在排序后将这些文件写回Li。因此,跨两个级别移动一个文件的写入放大率可以高达10。对于大型数据集,由于任何新生成的文件最终都可以通过一系列压缩步骤从L0迁移到L6,所以写入放大可以超过50(L1到L6之间的每个间隙为10) 写入扩增随着数据库大小而增加的原因很简单。随着更多的数据插入数据库,键值对更有可能沿着级别进一步移动;换句话说,当从低级别压缩到高级别时,LevelDB会多次写入数据

读取放大

读取放大有两个来源。首先,要查找键值对,LevelDB可能需要检查多个级别。在最坏的情况下,LevelDB需要检查L0中的八个文件,其余六个级别中的每一个文件:总共14个文件 其次,要在SSTable文件中找到键值对,LevelDB需要读取文件中的多个元数据块。具体来说,实际读取的数据量是由(索引块+布隆过滤器块+数据块)给出的,例如,要查找1-KB键值对,LevelDB需要读取16-KB索引块、4-KB布鲁姆-过滤器块和4-KB数据块;总共24 KB。因此,考虑到最坏情况下的14个SSTable文件,LevelDB的读取放大率为24×14=336。较小的键值对将导致更高的读取放大率 读取放大也会随着数据集的大小而增加,因为对于一个小数据库来说,SSTable文件中的所有索引块和布隆过滤器都可以缓存在内存中。然而,对于一个大数据库来说,每次查找都可能触及不同的SSTable文件,每次都要支付读取索引块和布隆过滤器的费用

为什么LSM要排序

为了实现高效的查找(对于单个键和范围查询),LSM树在后台连续读取、排序和写入键值对,从而按排序顺序维护键和值,因此,相同的数据在其整个生命周期中被多次读取和写入

分层

内存中分为活跃跳表和不可变跳表,活跃跳表用来更新数据,不可变跳表会被dump到磁盘成为C0层的不可变sstable LSM结构引入了分层设计的思想。将所有的kv文件分为c0-ck 共k+1层。c0层是直接从不变的内存表中dump下的结果。而c1-ck是发生过合并的文件。由于ci+1 是ci中具有重叠部分的文件合并的产物,因此可以说在同一层内是不存在重叠key的,因为重叠key已经在其上一层被合并了。那么只有c0层是可能存在重叠的文件的。所以当要读取磁盘上的数据时,最坏情况下只需要读取c0的所有文件以及c1-ck每一层中的一个文件即c0+k个文件即可找到key的位置,分层合并思想使得非就地更新索引在常数次的IO中读取数据,每一层的数据量都是递增的,如C0层2M,C1层20M之类的,达到阈值就触发compaction

  • minor compaction:内存中的跳表dump到C0层成为sstable的过程 
  • major compaction:  Ck(k>=0)到下一层文件合并的过程 合并:k>0时,Ck层文件 + Ck+1层文件(这两层文件的key才会有重叠)进行合并成为Ck+1层的文件,C0层文件之间有key重叠,则合并输出C1层的sstable文件

MANIFEST文件

为了标记哪些SStable属于那一层因此要存在一个sstable的元数据管理文件,在levelDB中叫做MANIFEST文件。其中存储每一个sstable的文件名,所属的级别,最大与最小key的前缀。

预写日志

作为一个DB引擎,必须保证数据库进程崩溃前后的数据一致性,常见的做法就是使用预写日志 将所有的操作记录在一个仅追加的log文件中(称之为WAL),所有的写入操作都要保证写入WAL成功后才能继续,因此当数据库崩溃后写入WAL的操作将被回溯,反之则被丢弃(只有写入WAL成功才会回复客户端ack),wal是整体恢复才能保证数据一致性,但为了避免wal过大,会做定期的清理,将那些已经写入磁盘的数据清理掉,所以wal通常也不会很大,每个wal就是sstable文件,每个wal文件其实对应一个内存表,当这个内存表被dump,对应的wal文件也将失去作用,数据库恢复的时候,只需要重放那些没有dump的内存表即可。

新增

先写wal日志,即先写LSM日志,然后更新内存跳表即可,达到阈值触发compaction

删除

先写wal日志,即先写LSM日志,然后更新内存跳表即可,达到阈值触发compaction

修改

先写wal日志,即先写LSM日志,然后更新内存跳表即可,达到阈值触发compaction

查找

先从内存跳表中查,没找到依次查Ck层文件,其中C0层每个文件都需要查,Ck(k>0)层文件因为没有重叠只需查一个文件即可,查到就返回,没查到就继续往下一层查找,查找具体的sstable文件时,该文件对应的元数据会保存了该sstable保存的最小和最大key用来决定是否对该sstable进行查找,查找sstable时由于是排序的,所以可以通过类似二分查找来定位查找,另外还可以通过布隆过滤器来判断该key来进行过滤判断,不存在的话就不需要查该sstable了

LSM优化

读取性能的瓶颈在于读写放大以及合并压缩过程的抖动,以下列出LSM可能选择的优化方向:

  • 跳跃合并:传统合并方式是Ck层文件合并输出到Ck+1层,跳跃合并是key直接放到Ck+N层文件,中间层没有该key,减少了每层之间数据的compaction
  • 冷热分离:类似lru方式,热数据放到内存中
  • 并行化IO调度:ssd多线程,线程池进行IO
  • 二级索引:value中再次建立索引,如学校 -> 班级 -> 学生数,班级 -> 学生数就是二级索引
  • 原子性事务:多个操作放在一个事务中,要么一次执行完毕或者全部不执行,不能执行到一半
  • kv分离存储:wisckey论文的核心思想

Wisckey介绍

WiscKey诞生的背景

存储环境正在迅速变化,SSD有三个特点:

  • SSD的随机和顺序性能之间的差异远没有硬盘那么大,因此,执行大量顺序I/O(sstable排序以及compaction排序)以减少后来的随机I/O的LSM树可能会不必要地浪费带宽,即维护顺序的IO消耗可能在SSD上的roi收益不大,因为ssd上顺序IO和随机IO的差距并不大

  • 固态硬盘具有很大程度的内部并行性;构建在固态硬盘上的LSM必须精心设计以利用上述并行性
  • 固态硬盘可能会通过重复写入而磨损;LSM tree中的高写入放大会显著降低设备寿命

这些因素的结合极大地影响了固态硬盘上的LSM树性能,降低了90%的吞吐量,增加了10倍以上的写入负载。虽然在LSM树下用固态硬盘替换硬盘确实提高了性能,但使用当前的LSM树技术,固态硬盘的真正潜力在很大程度上没有实现。在高性能固态硬盘上使用LSM树可能会浪费很大一部分设备带宽(因为SSD上面三个特点没有被充分利用),这是WiscKey诞生的背景,可以用来最大限度地减少SSD上的读写放大

WiscKey四个关键思想

  • key和value分离,即value不跟key保存在LSM树中,value单独用一个文件即value log来保存
  • 为了处理未排序的值(value log的value访问是随机的),range查询是得到一个连续的key,但是各个key对应的value在value log中是随机的,所以range查询是随机查询的,为了解决这个问题,wisckey使用SSD并行随机读取特性,应该是通过一个线程池来实现的
  • WiscKey利用独特的崩溃一致性和垃圾收集技术来有效管理值日志,这里应该是管理value log的机制,垃圾收集技术用来定期回收value log中的数据
  • WiscKey通过删除LSM树日志而不牺牲一致性来优化性能,从而减少小写入带来的系统调用开销,定期删除LSM日志(wal日志),value log刷盘后,对应的lsm日志就可以被删除

通过上面四个关键技术,可以降低传统LSM的读写放大

设计目标

  • 低写入放大:提高工作负载性能和提高SSD寿命(每次写入都会让SSD的寿命减少)
  • 低读取放大:提高查询吞吐,读放大太大相当于加载到内存中的数据其缓存的效率不是很高
  • SSD优化:通过将其I/O模式与SSD设备的性能特性相匹配,就是利用顺序写入和并行随机读取来充分利用设备的带宽
  • 功能丰富的编程接口:wisckey旨在支持现代化的特性,这些特性使得LSM树更加流行,例如范围查询和快照查询,范围查询允许扫描连续的键值对序列,快照查询就是查询特定数据库的某个快照的数据
  • 真实的键值大小:意思就是wisckey旨为真实的键值大小提供高性能

kv分离介绍

kv分离诞生的背景

  • 解决传统lsm读写放大的问题
  • ssd的随机写和顺序写的差距没有机械硬盘的差距大,range查询时是随机读,通过并发,预读来降低影响
  • 适合value比较大的kv数据存储

在SSD上使用LSM技术带来两个问题:

  • 第一:写放大缩短了SSD的使用寿命
  • 第二:传统的LSM无法充分发挥SSD的并行读写特性。

KV分离存储

本次要讲的wisckey论文的核心思想,大概意思是value单独存储在value log文件中,而新的value是一个指针,这个指针指向了value log中该value的位置,而不是跟LSM传统的方式一样将kv数据放在一起存储,即wisckey中将key与value分离存储,value仅存储在vlog中以仅追加的方式,而key存储在之前的lsm tree结构中,这样做优点如下:

  • lsm仅存储固定大小的key使得其存储占用变小,在内存中可以同时存储更多的key进而提高了缓存key的数量,间接的降低了读放大问题
  • merge过程中,由于value单独存放在value log中,读写的磁盘IO数据量减少,从而减少了写放大,即不需要频繁移动vlaue的值,所以写放大减少

假设一个16-B键,一个1-KB值,键的写扩增为10(在LSM树中),WiscKey的有效写扩增仅为(10×16+1024) / (16+1024)=1.14 对于随机读请求,固态硬盘远高于机械硬盘,而对于范围查询,由于真正的value都存储在vLog中因此是无序的,所以进行范围查询就是需要进行随机读取(先从lsm顺序读key再逐个随机读value),这必然造成性能的下降,传统的随机读取是串行的难以发挥固态硬盘并行随机读取的特性,因此在wisckey中根据迭代器的调用方法prev,next 来从排序好的lsm中预读取一定的key到内存中,加速随机的范围查询性能,这种预先读取是异步进行的,充分发挥固态硬盘的并行读取性能。

实现细节

数据布局

KV分离设计

  1. 在sstable文件中数据布局: <key, addr(vlogName,offset,size)>
  2. 在vlog文件中的数据布局: <keySize,valueSize,key,Value>

vlog文件其实跟wal是一样的,只需存在一份这样的日志文件即可,这就是为什么vlog中key和value都要保存

插入

当用户在WiscKey中插入键值对时,该值首先被追加到vLog中,然后该键与该值的地址一起被插入到LSM树中

删除

删除一个键只需将其从LSM树中删除,而无需触摸vLog。vLog中的所有有效值在LSM树中都有相应的键;vLog中的其他值无效,将被垃圾收集

查询

当用户查询key时,首先在LSM树中搜索该key,如果找到,则检索相应值的地址。然后,WiscKey从vLog中读取该值

随机查询

  1. 先访问内存表是否命中key,如果找到地址信息判断是在内存中还是磁盘中(LRU缓存)
  2. 在内存中被缓存了value则直接返回,否则去磁盘中查找,根据vlog的名字找到具体的vlog文件
  3. 然后根据offset定位字节的首地址,根据size读取内容并返回
  4. 基于一定策略将整个vlog涉及的bolck缓存下来

查找性能优于LevelDB的原因

由于WiscKey的LSM树比LevelDB小得多(对于相同的数据库大小),查找可能会在LSM树中搜索更少级别的表文件,并且LSM树的很大一部分可以很容易地缓存在内存中。因此,每次查找只需要一次随机读取(用于检索值),因此查找性能优于LevelDB。例如,假设16-B键和1-KB值,如果整个键值数据集的大小为100GB,那么LSM树的大小只有2GB左右(假设一个值的位置和大小需要12-B的成本),这可以很容易地缓存在内存超过100-GB的现代服务器中

范围查询

  1. 根据迭代器 next 还是 prev判断 是在游标之前读还是之后读,范围查询是通过迭代器来查的,每次读取value都是随机查询,即range操作就是随机读,因为value是保存在另外一个文件中的,适合在ssd上,即随机读写和顺序读写差距不大的场景
  2. 预先读取一定的key,交由底层的线程池异步的取ssd中获取数据,即并发异步查询,但还是有一些性能损失的
  3. 将异步结果缓存在内存中 等到迭代器的调用

随机/顺序写入

  1. 将set操作先写入vlog日志中(存储key的作用之一就是既作为预写日志又作为值日志)
  2. 然后将返回的地址信息写入LSM中返回
  3. 返回写入成功

合并压缩

  1. vlog分为多个文件 其中存在一个活跃vlog文件 用于写入数据作为head地址
  2. 最先写入的的日志在最后的vlog中 存在tail地址
  3. 多个写入线程通过head地址处追加日志
  4. 而只有一个后台线程执行垃圾收集运行在尾部,即访问tail地址
  5. 每次选择一个vlog文件(通过tail地址得到vlog文件)的内容去lsm结构中随机查询(可并行化) 将没有失效的key重新写会到head地址处重新追加到vlog中
  6. 然后更新lsm中这些key的新地址
  7. 并释放老的vlog文件
  8. 这一过程中需要先将数据写入新的vlog文件后刷新到固态硬盘后异步更新索引,更新了索引后才能删除老的vlog文件
  9. 最后删除老文件 以防止在此过程中进程崩溃造成数据丢失

故障恢复

  1. 在wisckey的设计中预写日志就是值日志
  2. 因此引擎进程只需要定时保存 head和tail的地址即可
  3. 数据库恢复时需要获取崩溃前最新的地址然后从tail到head将日志进行redo即可
  4. 同时为了保证一致性在查询key时要做一些必要的一致性检查
    1. 当前key如果在tail与head索引范围外则忽略
    2. 当前位置上的值具有的key与查询的key不匹配则忽略
    3. 发生上述情况时,引擎直接返回错误信息

kv分离带来的问题

  • vLog文件会不断增大,那么就需要合并,如何合并才能保证对性能的影响最小化?
  • 同时由于移动了value的位置,LSM结构中维护的value的位置信息也要更新。数据具体如何布局?
  • vLog日志如何拆分?
  • wisckey崩溃后如何恢复才能保证数据的一致性呢?

即键和值的分离使得范围查询需要随机的I/O,这种分离使得垃圾收集和崩溃一致性都具有挑战性,通过下面几种方法来解决这些挑战。

并行范围查询

对于范围查询,LevelDB为用户提供了一个基于迭代器的界面,带有Seek(key)、Next (), Prev (), Key()和Value()操作。要扫描一系列键值对,用户可以首先将Seek()到起始键,然后调用Next()或Prev()逐个搜索键。要检索键或当前迭代器位置的值,用户可以分别调用Key()或Value () 由于键和值单独存储在WiscKey中,范围查询需要随机读取,因此效率不高,为了提高范围查询的效率,WiscKey利用SSD设备的并行I/O特性在范围查询期间从vLog中预取值。其基本思想是,对于SSD,只有key需要特别关注才能有效检索。只要key被有效检索(意思这个key没有被删除存在于LSM树中),范围查询就可以使用并行随机读取来有效检索值 预取框架可以很容易地与当前范围查询接口相匹配。在当前接口中,如果用户请求范围查询,则向用户返回迭代器。对于迭代器上请求的每个Next()或Prev(),WiscKey跟踪范围查询的访问模式。一旦请求连续的键值对序列,WiscKey就开始依次从LSM树中读取许多以下键。从LSM树中检索的相应值地址被插入队列;多个线程将在后台并发地从vLog中获取这些地址

垃圾收集

在WiscKey中,只有无效的键才会被LSMtree压缩回收。由于WiscKey不压缩值(compact),它需要一个特殊的垃圾收集器来回收vLog中的空闲空间 WiscKey的目标是一个轻量级的在线垃圾收集器。为了实现这一点,我们引入了对WiscKey基本数据布局的一个小改动:在vLog中存储值的同时,我们还将相应的key与值一起存储。新的数据布局如下图所示:元组(key大小、值大小、key、值)存储在vLog中WiscKey的垃圾回收旨在将有效值(不对应于已删除的key)保留在vLog的连续区域中,如上图所示。该区域的一端,头,总是对应于vLog的末端,在该末端新值将被追加。该区域的另一端,称为尾,是垃圾回收在触发时开始释放空间的地方。只有头和尾之间的vLog部分包含有效值,并且将在查找过程中进行访问。在垃圾收集过程中,WiscKey首先从vLog的尾部读取一大块键值对(例如,几个MB),然后通过查询LSM树来找到这些值中哪些是有效的(尚未覆盖或删除)。WiscKey然后将有效值追加回vLog的头部。最后,它释放块之前占用的空间,并相应地更新尾部 为了避免在垃圾收集过程中发生崩溃时丢失任何数据,WiscKey必须确保新添加的有效值和新尾部在实际释放空间之前在设备上是持久的。WiscKey通过以下步骤实现了这一点。将有效值追加到vLog后,垃圾收集在vLog上调用fsync()。然后,它以异步方式将这些新值的地址和当前尾部添加到LSMtree;尾部存储在LSM树中,作为 < tail标识 , tail-vLog-offset>。最后,回收vLog中的空闲空间

崩溃一致性

当用户查询键值对时,如果WiscKey无法在LSM树中找到该键,因为该键在系统崩溃期间丢失了,WiscKey的行为与传统的LSM树完全相同:即使该值在崩溃前已在vLog中写入,以后也会被垃圾收集 如果该键可以在LSM树中找到,则需要额外的步骤来保持一致性,在这种情况下,WiscKey首先验证从LSM树中检索的值地址是否在vLog的当前有效范围内,然后验证找到的值是否与查询的key相对应,如果验证失败,WiscKey假设值在系统崩溃期间丢失,从LSMtree中删除key,并通知用户未找到key。由于添加到vLog的每个值都有一个包括相应键的头,可以直接验证vLog中的value是否是该key对应的value(vLog中也保存了key,可以直接比较key即可);如果需要,可以很容易地在头中添加一个魔术数字或校验和 如果用户要求同步插入,wisckey在执行同步插入到内存LSM树之前,会通过刷新vLog实现同步插入

优化与改进

值日志写缓冲区

对于写入密集型工作负载,向文件系统发出大量小写入(调用系统调用write)可能会引入明显的开销,对于小写入,每个系统调用的开销显著聚集,导致长运行时间。通过大写入(大于4 KB),设备吞吐量将得到充分利用,这里说的是多个小写入聚合写入,提高吞吐量,而不是每次都调用系统调用write,减少系统调用开销,从而提高吞吐量,如下面实验,写入10G,不同的写入数据量所消耗的时间分布:为减少写入的系统调研次数,多个小key的写入会被缓存在内存中汇聚在一起统一的写入lsm的sstable中,但会优先写入vlog中当作预写日志处理。为了减少开销,WiscKey会在用户空间缓冲区中缓冲值(value),并且只有当缓冲区大小超过阈值或用户请求同步插入时才会刷新缓冲区,此外,WiscKey only issues large writes and reduces the number of write() system calls. 为了查找,WiscKey首先搜索vLog缓冲区,如果没有找到,再去从vLog中读取。显然,这种机制可能会导致一些数据(被缓冲)在崩溃期间丢失;崩溃一致性保证类似于LevelDB的实现,即使用LSM日志,当vlog buffer刷盘后,该lsm日志就可以被删除

优化LSM树日志

日志文件通常用于LSMtree,LSM树跟踪日志文件中插入的键值对,这样,如果用户请求同步插入并且发生崩溃,可以在重新启动后扫描日志并恢复插入的键值对 在WiscKey中,LSM树仅用于键和值地址。此外,vLog还记录插入的键,以支持上一节所述的垃圾收集。因此,可以避免写入LSM树日志文件,而不会影响正确性,其实还是会有用到LSM日志,vlog buffer刷盘后,该LSM会被删除掉这段大概意思是通过在LSM树中记录一个vLog的head(head标识,head-vlog的offset),可以减少启动时扫描vLog的数据量,只需从head开始扫描即可,直到扫描vlog结束,并且LSM树保证了插入到LSM树的key将以插入的顺序被恢复,这个优化就是故障一致性

空间放大率

数据存储的实际的大小与逻辑上的大小比值用来衡量空间放大情况,对于固态硬盘来说其价格昂贵,降低空间放大率会大大的节省存储成本,这也是wisckey的下一个优化点。

在线垃圾收集

GC过程会造成引擎的性能尖刺,通过并发的在线的分批次的进行GC操作来对前台读写性能影响。

小Value的存储

经论文的测试数据value大于4KB时其读取性能才会有极大的提升,因此可以设置一个阈值,当value大于此阈值时才进行KV分离,而再次之前使用传统lsm-tree模式。

实现

wisckey是基于Leveldb 1.18版本,当创建一个新的数据库时会创建了一个vlog,并且管理key和value addr在LSM树种,这个vlog在内部被多种组件以不同的访问模式访问,例如:一个查找是随机读取vlog,而垃圾收集则顺序从vlog尾部读取,append数据到vlog的头部,我们使用在不同的访问模式下,使用posix_fadvise()系统调用预先告诉操作系统将要进行的访问模式,以便操作系统进行优化(原文:We use posix_fadvise() to predeclare access patterns for the vLog under different situations.)对于范围查询,WiscKey维护一个包含32个线程的后台线程池。这些线程在线程安全队列中休眠,等待新的值地址到达。当触发预取时,WiscKey将固定数量的值地址插入工作队列,然后唤醒所有休眠线程。这些线程将开始并行读取值,自动将它们缓存在缓冲区缓存中 为了有效地垃圾收集vLog的可用空间,我们使用了现代文件系统的空洞功能(fallocate系统调用),大概意思是通过该系统调用的文件打洞特性,垃圾收集更加高效,如下:原文如下:To efficiently garbage collect the free space of the vLog, we use the hole-punching functionality of modern file systems (fallocate()). Punching a hole in a file can free the physical space allocated and allows WiscKey to elastically use the storage space. The maximal file size on modern file systems is big enough for WiscKey to run a long time without wrapping back to the beginning of the file; for example, the maximal file size is 64TB on ext4, 8EB on xfs, and 16EB on btrfs. The vLog can be trivially adapted into a circular log if necessary

评价

顺序负载性能吞吐量对比

image.png

leveldb在不同阶段的时间消耗百分比

image.png

随机负载性能吞吐量对比

image.png

写放大对比

image.png

随机写延迟时间分布对比

image.png

随机查找对比

image.png

范围查性能对比

image.png

垃圾收集对比

image.png

结论

在本文中,我们提出了WiscKey,这是一种新颖的基于LSM树的键值存储,它将键和值分离以最小化写和读放大。WiscKey的数据布局和I/O模式针对SSD设备进行了高度优化。我们的结果表明,WiscKey可以显著提高大多数工作负载的性能

业界实现

badger,wisckey的经典实现,用来存图数据库中的kv数据,一般value比较大,所以用badger比较适合

参考资料