MioDB论文笔记
总体介绍
原文标题为Revisiting Log-Structured Merging for KV Stores in Hybrid Memory Systems
LSM-Tree一直有周期性写停滞和写放大的问题,在传统DRAM-SSD系统架构里解决这一问题还是十分困难的。而NVM(持久化内存)有希望取代SSD,为优化基于LSM-Tree的KV存储性能提供了新的机会。
过去也有一些工作使用NVM对基于LSM-Tree的KV存储性能进行优化,但是这些工作都忽略了一个问题:传统LSM-Tree的数据序列化和压缩速度太慢,因此可能会阻塞数据从DRAM到NVM的Flush。 如果当DRAM的MemTable累积了突发性的大量写入,就需要时间来对KV项进行序列化,再将数据装入LSM-Tree的
论文的工作如下:
1、设计了多级skip list(又叫PMTable,替代LSM实现的SSTable),以充分利用NVM的字节可寻址性进行KV存储,并利用One-Piece Flushing(代替原LSM-Tree从immutable MemTable到
2、将Zero-Copy Compaction与Lazy-Copy Compaction相结合(替代LSM-Tree中的Compaction),以减少写停滞和写放大。
3、提出了并行Compaction方案(即不同层到下一层的Compaction可以同时进行),同时还成功协调了LSM-Tree的Flush和Compaction,从而进一步减少写停滞,提高查询性能。
4、基于LevelDB实现了MioDB,并开源了代码。
设计原则
论文主张在MioDB中采用以下几项设计原则,以充分发挥NVM的优势:
1、NVM内管理KV数据的数据结构(如LSM-Tree传统的SSTable)应与DRAM Buffer的结构(如LSM-Tree的MemTable)兼容,以尽量减少数据序列化/反序列化的成本。
2、数据的Flush操作(从immutable MemTable到
3、多级skip list之间的数据Compaction应足够快,且不应造成写放大问题。
4、写入性能优化不应影响KV存储的读取性能。
论文实现
MioDB Architecture
如图所示,MioDB仍然使用基于DRAM的MemTable来缓存写入请求。不过,MioDB使用skip list(PMTable)取代了传统的SSTable,以管理NVM中的持久化数据(需要注意这里没有SSD,数据最后只存放在NVM里)。在这里,论文仍然使用树状结构来表述跨多级的PMTable Compaction。然而,MioDB的逻辑结构与LSM-Tree的完全不同。在NVM中,MioDB维护着一个由
在LSM-Tree中,每层中的SSTable数量有限,而MioDB则不同,它可以在每层中容纳无限的PMTable,而不会阻碍One-Piece Flush或跨层PMTable之间的Compaction。
论文同时提到MioDB支持将Data Repository建立在大容量SSD上,也支持在Data Repository里用多级SSTable来替代PMTable,并仍然利用LSM-Tree原有的方法进行Compaction。这是为了兼容之前已经实现并运行的应用程序。
One-Piece Flushing
当DRAM中的MemTable已满时,MioDB应该将其变为immutable MemTable,并将其Flush到NVM中。在以往的基于LSM-Tree的KV存储(包括之前几篇使用NVM进行优化的工作)中,Flush操作会对MemTable中的KV逐一序列化并复制到磁盘上的SSTable中。
论文提出了One-Piece Flushing技术,以高效地将immutable MemTable持久化到NVM中。在MioDB中,MioDB为DRAM里的MemTable和NVM里的PMTable分配了相同大小的连续内存空间。同时DRAM里的MemTable结构和NVM里的PMTable结构是兼容的。这样只需一次memcpy,就能将MemTable转换为PMTable,而无需进行数据定位和数据合并。
One-Piece Flushing可以在后台执行,不会阻塞读/写操作。当一个MemTable已满时,MioDB会将其变为immutable MemTable,并创建一个新的MemTable来进行写操作。后台线程会将immutable MemTable从DRAM Flush到NVM。在此期间,DRAM中这个原先的immutable MemTable仍可响应读取请求,直到Flush结束后这个immutable MemTable占用的内存空间才会被回收。
Zero-Copy Compaction
MioDB利用NVM的字节可寻址特性和skip list的数据结构,为Elastic Buffer设计了一种Zero-Copy Compaction方案。各个PMTable里的Compaction只需更新skip list中的指针,而无需移动数据节点,因此大大降低了写放大和Compaction的成本。
这里把某一级中已经存在的PMTable称为oldtable,把新插入的PMTable称为newtable。在Elastic Buffer中,每次选择每一级中最旧的两个PMTable执行Compaction操作,然后将合并后的PMTable插入下一级。图(a)展示了oldtable和newtable的初始状态。PMTable中的数据节点按Key升序排序。用Seq表示KV对的序列号。为简单起见,把具有Key x和Seq y的数据节点称为节点
首先先看下图(a)里
再讨论下唯一数据节点和重复数据节点。看图(a),newtable一行,
需要注意的是,Zero-Copy Compaction将每一层的newtable(实际上就是来自于上一层的oldtable)合并到该层的oldtable里,也把每一层最旧的PMTable(实际上也是oldtable)视为下一层的newtable,合并到下一层的oldtable里。
图(b)展示了如何将唯一数据节点(即key在一层的PMTable里只有一种版本)合并到oldtable中。以
图(c)展示了重复数据节点是如何合并到oldtable中的。如果同一层里一个key在两个PMTable里有不同版本的节点(即Seq不同),称该节点为重复节点。在图(b)里上述节点
首先使用插入标记指向
论文提出,利用插入标记,可以支持Compaction与Query同时进行。
Lazy-Copy Compaction
虽然Elastic Buffer能有效处理突发写入,但各级PMTable中的冗余数据(例如同一个key的更旧版本不会被查询到,是冗余的)会消耗大量NVM空间。另一方面,高度数据冗余也会降低查询性能。提出了Lazy-Copy Compaction来收集各级PMTable中的垃圾(冗余的KV项),并使用一个Huge PMTable作为Data Repository来存储剩余数据。注意到,Data Repository在MioDB架构里也是
Lazy-Copy Compaction的过程如下:
1、在
2、如果Data Repository(
3、如果第一步条件成立,就会将新创建的节点插入到
4、
与Zero-Copy Compaction不同,Lazy-Copy Compaction里从
Parallel Compaction
由于MioDB只会对单层中最旧的PMTable进行Compaction,因此不同层中的数据Compaction是独立的。因此,论文提出采用并行的Compaction来加快所有层级的数据的Compaction的速度。
尽管RocksDB已经提供了并行Compaction的简单实现,但它对减少写停滞的作用十分有限。在MioDB中,因为Elastic Buffer每层的容量都不受限制,所以Elastic Buffer可以保证无阻塞的Compaction。同时,由于MioDB总是在单层中选择两个最旧的PMTable进行Compaction(来自上一层Compaction的PMTable至少是第三旧的),因此每层的Compaction与其他层的Compaction完全无关。由于上面两个原因,可以使用线程并行执行每层的Compaction。对于
Read Optimizations
在每个PMTable中,数据都是有序的。因此,PMTable内查询速度非常快。然而,即使在单层中,多个PMTable的键范围也经常重叠。在最糟糕的情况下,查询线程必须逐个检索所有PMTable。为了提高读取性能,论文提出了以下两种优化方案:
1、增加单个PMTable的容量,以利用PMTable内快速查询的优势。
2、使用Bloom过滤器缩小查询范围。
Crash Consistency
与LevelDB和NoveLSM等基于LSM-Tree的KV存储类似,MioDB利用预写日志(WAL)来保证写入DRAM Buffer里的数据的故障恢复。对一个个KV项,MioDB首先按顺序将它们添加到NVM中的持久化日志中,然后插入到DRAM里的MemTable中。
因为DRAM Buffer的日志(存储在NVM里)可用于保证崩溃后的一致性,当DRAM Buffer中的数据被Flush到NVM时,MioDB可以直接将数据复制到NVM,而不需要单独的日志。假设在Flush时崩溃了,只需要NVM里的日志就可以恢复之前写入到MemTable的数据,再次Flush到NVM里。在Zero-Copy Compaction期间,由于MioDB使用原子性写入来更新PMTable中的指针,并且不移动数据节点,因此MioDB PMTable在系统崩溃后仍能保证数据的一致性。