首页 > > > 【ATC 2018】HashKV

以 LevelDB 和 RocksDB 为代表的 LSM-tree key-value 存储,被广泛的应用,所以当前针对其优化的研究非常多,在最近几年的顶会上都有,这里将介绍 USENIX ATC 2018 的一篇文章 HashKV [2],其是对 FAST 2016 中 WiscKey [1] 的优化。那么首先来介绍下 LSM-tree 和 WiscKey。
LSM-tree 被应用在 Bigtable,HBase,Leveldb,RocksDb 等中,这里以 Leveldb 为例子,如下图:

其写入首先将数据以 append 的方式写入 log 中,然后写入内存中的 memtable,就可以返回,因为事先写入了 log,所以保证的持久性;memtable 到达一定的大小之后转变成不可写入的 immutable,然后在被持久化为 是stable 文件;sstable 的文件会定期的做 Compaction 合并到下一个 level 中,以便将老数据推到高层的 level 中,并实现删除 key-value 的回收,如上图所示:
优点:
缺点:
缺点也很明显,就是 I/O 放大:
文献 [1] LevelDB 和 RocksDB 的 write amplifications 达到 50X 之多,在顺序写和随机写相差 100X 甚至 1000X 的 HDD 时代,LSM-tree 的收益是明显的,反之在顺序写和随机写相差不大的 SDD 时候,尤其是 NVME SSD 和 Optane 设备的出现,进一步缩小了顺序写和随机写的差距(< 10X),所以人们开始思考对 LSM-tree 进行优化了。最近比较火的是 FAST 2016 的文章 WiscKey。

WiscKey 为了减少 read/write 的放大,决定将 key-value 分开,减少 LSM-tree 的 size,从而减少 Compaction 对 write amplifications,其大致的做法如上图,将 key-value 分离(其实和 bitcask[3] 的思路是类似的):
key + meta data 存放在 LSM-tree 中,也就是 LevelDB 或者 RocksDB 中,这样 LSM-tree 中数据量很少,那么 Compaction 只有 LSM-tree 中的 key + meta data 在移动,而在 vLog 中 key+value 并不会动,自然造成的 write amplification 自然会小很多,实际上由于数据量少了,read 可能需要查询的 level 数也变少,所以对 read/write amplification 都有一定的效果
value 单独存放在 VLog 中,vLog append 的写入 key-value。为了释放 VLog 中被删除的 key-value,Wisckey 需要对 vLog 进行 GC,GC 是从 tail 读,然后去 LSM-tree 中查询有没有这个 key,如果没有,说明被删除了,否则,又 append 到 head,那么就会存在一定的写放大,实际上这里也有很多需要考量的问题,空间放大和写放大如何权衡 ?如何控制 Gc 保证其不影响正常的 I/O ?
Notes
上图的顺序好像是画反了,上图是官方在会议上 presentation 的 ppt,在论文中描述上好像也有错误 ?
First, the circular log maintains a strict GC order, as it always performs GC at the beginning of the log where the least recently written KV pairs are located. This can incur a large amount of unnecessary data relocation (e.g., when the least recently written KV pairs remain valid)
感觉这个错误优点低级,不知道是不是自己看错了,关系的小伙伴可以一起验证下。如果作者理解错了,那么上面这段话就扯了。
回到正题,虽然减少了 write amplification,但是 GC 可不是省油的灯,原文作者认为在空间有限,且 update-intensive workloads,其实就是不允许空间放大太多,且更新很频繁的系统中会存在以下问题:

如上图,给出了空间放大有限,更新频繁的系统由于频繁的 Gc 造成 GC write amplification 非常严重。由此,作者给出了自己的解决方案 HashKV
目标场景:
(虽然 update-intensive workloads 下,确实 GC 放大严重,但是作者硬生生的还加上空间放大容忍度低这一条,哈哈,,,)
Architecture

其实 key-value 分离思路简单,但是关键还是要看 storage management,如 Figure 3 的体系结构图。
一个 Partation 是由一个固定大小的 main segment 和 若干个 log segment 组成的 segment group,当一个写入的 key-value pair 时候,如果 main segment 中有空间,则 append 到未满的 main segment 中,否则动态的分配 log segment 来存放
当 LSM-tree 更新完毕之后,这个 segment group 的 gc 就算结束了,之前的 segment 也就可以删除掉了,read/write 就会到新的 segment 中。
gc 的过程中,并不会影响 read/write,read 还是走之前的 LSM-tree 读,write 写入 gc 新写入的 segment
Hotness Awareness

cold k-v with a taggted(Currently, we treat the KV pairs that are updated at least once since their last inserts as hot, or cold otherwise ),在 GC 的时候,hot kv 继续写到 segment 中,对于 cold 的 kv,仅仅把 key 和 meta 存在 segment 中,value 存放在 vlog 中,和 WiscKey 的方法一样进行回收
Selective KV Separation
可以选择 k-v 是否分开,在 value 小的情况的下直接存放在 LSM-tree 中,反之则执行 k-v 分离。
Range Scans
4. 总结
参考文献
[1]. Arpaci-Dusseau R H, Arpaci-Dusseau R H, Arpaci-Dusseau R H, et al. WiscKey: Separating Keys from Values in SSD-Conscious Storage[J]. Acm Transactions on Storage, 2017, 13(1):5.
[2]. HashKV: Enabling Efficient Updates in KV Storage via Hashing. https://www.usenix.org/conference/atc18/presentation/chan
[3]. bitcask. http://downloads.basho.com/papers/bitcask-intro.pdf
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/30107046/viewspace-3145349/ ,如需转载,请注明出处,否则将追究法律责任。