SLM-DB:基于持久化内存PM的单层键值对存储(SLM-DB:Single-Level Key-Value Store with Persistent Memory)

论文原文:https://www.usenix.org/system/files/fast19-kaiyrakhmet.pdf

摘要:

本文调查了如何利用新出现的可按照字节寻址的持久化内存(Persistent Memory)来增强KV存储的性能。我们充分利用PM,提出了一种新型的KV存储,SLM-DB,这种存储同时利用到了B+树索引和LSM-tree的优点。我们提出的SLM-DB这种架构,具有更高的读性能和写性能,同时拥有很低的写放大和接近理想最优状态的读放大。在SLM-DB中,我们利用持久化内存来保存B+树的索引,利用LSM树把新插入的键值对保存在持久化内存的缓冲区中。SLM-DB仅有一层键值对组织在磁盘上,同时执行选择性的compaction来保证键值对是充分有序的,以便于范围查询更快。我们经验丰富的研究证明,默认配置下,同LevelDB相比,SLM-DB同样情况下的范围查询性能,拥有1.07-1.96倍的读带宽和1.56-2.22倍的写带宽。

1 简介

KV存储已经成为高效支撑不同的数据密集型应用,例如网页索引,社交网络,电子商务和云照片等的关键组件。分别基于B树和LSM树的两款典型KV存储都已经被大范围的使用。例如基于B树的存储和数据库,KyotoCabinet支持快速读取和范围查询。然而,基于B树的KV存储展现了差的写性能,这主要是因为总是发生多次少量的随机写磁盘,以及由于总是需要动态保持数据结构的平衡性而产生较大的写放大。因此,他们更适合读密集负载。

而基于LSM树的KV存储则被更好的优化以便于支持写密集负载,例如BigTable, LevelDB, RocksDB和Cassandra。基于LSM树构建的KV存储之所以能支持高写带宽,主要是由于将键值数据缓存在内存中,并批量顺序写入磁盘。然而,这样的存储拥有很大的缺陷,如很高的读写放大和很低的读性能,这是由于LSM树是一种拥有多层文件的数据结构,并且其中的键值对为了保证更快的查询,经常做合并和排序。

最近,对数据密集型应用同时拥有高性能读写能力的需求日益增长。雅虎,已经报道了在他们典型负载中,读写比例越来越相近的潮流。因此,优化KV存储同时拥有高读写性能变得非常重要。

支持字节寻址,非易失性的内存如PCM,自旋转移矩MRAM和3D XPoint等已经为提升内存和存储系统的性能,提供了新的机会。研究指出,持久化内存拥有和DRAM相似的读性能,更高的写时延(最高5倍)和更低的带宽。持久化内存相比DRAM,拥有更大的容量和密度。然而,持久化内存更被希望用来和HDD和SSD混布。比较典型的,对于大规模KV存储,数据仍然存储在磁盘上,同时持久化存储用来提升性能。需要重点指出的是,已经有早期的尝试,针对持久化内存,设计一个基于LSM树的KV存储。然而,研究如何在基于混合部署持久化内存和硬盘的新型KV存储系统中,持久化内存可以承担一个更重要的角色而不局限于大型的内存写buffer或读缓存,对实现更优越的性能来说,仍然是非常重要的。

在本文中,我们研究如何利用持久化内存来提升KV存储的性能。我们提出了一种新型的KV存储,SLM-DB,通过利用持久化内存,同时吸纳了B+树索引和LSM树实现的优点。SLM-DB同时拥有非常高的读写性能,并拥有较低的写放大和接近理想状态的读放大。
在SLM-DB中,我们利用B+树来存储索引键值对。利用持久化的B+树索引,我们可以加速查询key(而不需要布隆过滤器)。为了保持高的写带宽,我们利用LSM树组织新插入的键值对插入持久化内存的写buffer,完全消除前台写log的同时提供数据持久化。

在SLM-DB中,键值对存储在单层组织的磁盘文件中。由于SLM-DB可以充分利用B+树来查询,就没有必要保证键值对是有序的,这大幅度的降低了写放大。然而,过时的键值对需要gc。同时SLM-DB也需要存储在磁盘上的键值对保证一定程度的顺序性,以便于提供更好的范围查询性能。因此,SLM-DB也设计了可选compaction计划,在单层上执行严格合并键值对。

本文的主要贡献包括:

  • 我们设计了一款单层KV存储,保留了通过LSM树实现的高写带宽性能,同时集成了B+树来索引键值对。另外,我们通过持久化内存容纳新插入的键值对,避免了对磁盘的前台写log放大。
  • 对于可选compaction,我们设计了3种计划,基于1)活跃键占文件比例,2)B+树叶子节点被扫描次数,3)范围查询的顺序性程度。
  • 我们实现了基于LevelDB的SLM-DB并集成了B+树实现。SLM-DB被设计为即便系统发生故障,单层LSM树和B+树也可以保证数据一致性。我们使用db_bench中的microbenchmarks和YCSB对应现实工作负载。我们经验丰富的研究证明,默认配置下,同LevelDB相比,SLM-DB同样情况下的范围查询性能,拥有1.07-1.96倍的读带宽和1.56-2.22倍的写带宽,同时仅仅只有LevelDB的39%的磁盘写IO平均数量。

这篇论文剩下的部分组织如下。第二章讨论了LSM树存在的读性能差和读写放大比例过高的问题以及持久化内存在KV存储中的应用。第3章提出了SLM-DB的设计和实现。第四章讨论了KV存储操作是如何基于SLM-DB实现的。第五章讨论了SLM-DB如何在系统故障的情况下恢复。第六章评估了SLM-DB的性能,展示了我们的性能测试结果。第7章讨论了持久化内存的成本和并行化。第八章讨论了相关的工作。最后第九章总结了本文。

2 背景和愿望

在本章节,我们首先聚焦LevelDB,讨论基于LSM树构建的KV存储的重大缺陷。其他基于LSM树构建的KV存储如RocksDB等也存在相似的结构和问题。然后我们讨论考虑如何在KV存储中使用持久化存储。

2.1 LevelDB

LevelDB是一个受到Google Bigtable激发,被广泛使用的KV存储,它实现了LSM树。LevelDB支持基本的KV存储操作如put操作,将键值对放入KV存储。get操作,返回请求键关联的值。范围查询操作,返回所有满足查询范围内键对应的值并可以通过迭代器遍历所有键值对。在LevelDB的实现中,LSM树拥有两个主要结构,驻留在内存中的MemTable和Immutable MemTable,以及保存在磁盘上的多层SSTable文件,如图1所示。

这是图片

MemTable和Immutable MemTable基本上是已经排序过的跳表。MemTable存储最新插入的键值对。MemTable一旦填满,LevelDB就会把它转换为Immutable MemTable并新建一个MemTable。后台线程会把Immutable MemTable下刷到磁盘,键值对排好序,按照SSTable的文件格式。需要注意,删除键值对实际上是插入值为删除标识符的键值对。

上述插入操作期间,为了能保证从系统故障中恢复,新的键值对必须在插入MemTable之前先写入WAL日志。键值对最终在Immutable MemTable中最终下刷磁盘之后,WAL日志会被删除。然而,由于写性能问题,LevelDB并不会主动调fsync()确认写入WAL日志文件的键值对下刷磁盘。在我们的实验中,插入值大小为1KiB,总数据量在8GiB的数据集到数据库中的时候,开启fsync会导致写性能
下降12倍。因此,这是一种数据一致性和高性能之间的权衡。

对于磁盘部分的组件,LevelDB被组织成多层,从L0到最高Lk。每一层,除了L0,都拥有多个排好序的SSTable文件,单层内多文件内的键不重叠。每一层都有受限的容量,更高层可以容纳容量更大的SSTable文件,例如每一层都比低层级的文件容量大10倍。

为了保持这种等级分明的层级结构,当Lx层超过限制,后台compaction线程就会选择Lx层的一个文件。并将其中的键值对迁移到Lx+1层,这期间伴随Lx+1层相关键值对和Lx层键值对的合并和重新排序。当键值对排序的时候,如果同样的键存在,Lx+1层的会被Lx层的覆盖,因为低层的数据总是更新的。这样就保证了同一层键值对总是唯一的。L0层的数据下刷磁盘,不遵循合并和排序,原因是保证更高的写带宽,这导致L0层存在重复的键。总之,通过compaction,LevelDB不仅保证SStable文件在同层保序以提供快速的查询,同时也做了gc。

LevelDB同时也保证当前所有SSTable的元数据放在MANIFEST文件中。元数据包含了每一层SSTable文件的列表和每个SSTable文件键的范围。compaction过程中,SSTable元数据会记录包括删除在内的修改。一旦compaction完成,这些修改会首先存入MANIFEST文件,然后过时的SSTable文件会被删除。从这个角度上讲,即便当系统崩溃发生在compaction期间,LevelDB也可以通过恢复,返回一个一致的KV存储。

2.2 LevelDB的局限性

读性能慢。对于读操作,如单点查询,LevelDB首先查询MemTalbe和Immutable MemTable。如果内存中查找失败,就会从低到高,到每一层SSTable文件中查询。每一层,通过先查询每个SSTable文件包含的起始键,定位到可能包含键的具体的SSTable文件。在这个文件中,再通过查询SSTable文件内索引,确认可能包含键的Block。因此,一个读操作可能要求至少两个block读,1次index block读和1次data block读。然而,如果data block不包含这个键,LevelDB还需要继续在下一层中重复相关步骤直到最高层。为了避免不必要的block读和重复搜索成本,LevelDB使用布隆过滤器来过滤block。

这是图片

表1展示了是否使用布隆过滤器来定位一个键值对在LevelDB中的随机读损耗明细。我们通过db_bench测试LevelDB的随机读时延。这个测试中,内存4GB情况下,在插入值为1KiB的20GiB数据集以后,立刻运行随机读负载(没有等compaction完成)。测试细节和结果会在第6章讨论。

每次读的定位开销,包括了查询SSTable文件是否包含键,查询block找到具体键值对和检查布隆过滤器的时间。并且,这里还包括了我们称之为非必要block读的开销。尤其指如果不考虑布隆过滤器而多读的多层各种不必要的block,或者考虑布隆过滤器但是拿到错误结果而引起的不必要block读。如表中所示,我们提出的SLM-DB使用B+树索引,这会在之后的章节讨论细节,定位开销大幅度缩减到几乎忽略不计的程度。在上述实验中,平均读和处理一个data block的时延对于三种KV存储都是682ms。

图2展示了当值大小不同的情况下,定位开销也会有很大的变化。图中展示了定位开销占总读的比例。我们发现当值大小变大,定位开销也会变大。当使用布隆过滤器,定位开销比例会相对减少,但是开销比例仍然达到惊人的36.66%。在这个实验中,随机读负载运行在compaction在从低到高层级进行的过程中。越大的值大小,会导致LevelDB需要查询多层中越多的文件,以及查询更多的布隆过滤器。因此对于64KiB的值大小,相比于1KiB值大小,使用布隆过滤器的LevelDB展示了6.14倍非必要读block的开销。

高读写放大 我们都知道基于LSM树的KV存储都有很高的读写放大。这种存储系统会保持排好序的层级结构在磁盘上,并保证数据顺序写入磁盘。因此,一个新插入的键值对需要持续的合并排序写入磁盘,并通过后台流程不停迁移到更高的层级。对于一个k层LSM树,写放大的比例可以达到最高10k。

读放大,在LSM树的结构中同样很高。这是因为对于给定的键,LevelDB可能需要检查多层文件才能找到。并且,为了在同一层找到键,Level需要至少读取data block,index block和布隆过滤器,这些数据量都远远超过了所需读取的键值对。

2.3 持久化内存

新出现的持久化内存(PM)如phase change memory(PCM), spin transfer torque(MRAM)和3D XPoint都支持按字节寻址和非易失性。持久化内存PM通过内存总线而不是块接口连接,因此最小原子写入单元通常是8byte。当持久化数据到PM中时,由于跟传统存储设备相比拥有更小的原子写入单元,我们必须考虑系统故障情况下的数据一致性。因此,更新数据的时候我们必须保证内存写顺序。

然而,现代处理器内存写操作可能以cache line为单位重排序来最大化内存带宽。为了获得保序内存写顺序,我们需要利用损耗较大的memory fence和cache flush指令集。同时,如果写入PM的数据超过8byte,数据可能在故障发生时部分更新,进而导致重新恢复之后的数据不一致。这时,就需要用到非常普遍的技术如日志和CoW,因此,持久化数据到PM上需要认真的设计和思考。

PM提供了全新的机会来克服现存KV存储的缺陷。越来越多的人希望利用PM来优化KV存储。基于LSM机制的KV存储已经开始利用PM重新设计。然而,探索新的设计也仍然重要,在本文中,我们就探索了一种KV存储,利用PM来持久化索引。

3 单层合并DB(SLM-DB)

本章提出了SLM-DB的设计和实现。图3展示了SLM-DB的架构图。SLM-DB利用PM来存储MemTale和Immutable MemTable。当前的MemTale和Immutable MemTable允许我们移除WAL机制,提供更加健壮的数据一致性。SLM-DB不同于LevelDB,仅基于单层L0的SSTable文件,因此命名为单层合并数据库。因此,SLM-DB不重写键值对到更低层磁盘文件中,在LevelDB中这可能发生多次。拥有持久化内存组件和单层磁盘组件,写放大被大幅降低。

为了优化单层SSTable文件的读操作性能,SLM-DB构造了一个持久化B+树索引结构在磁盘上。由于B+树用于索引键值对,相比于许多基于LSM树的KV存储,本DB就不需要在低层SSTable文件上对键值对进行排序。

然而,SSTable文件中由于更新而过期的键值对应该被及时删除以避免磁盘空间浪费。SLM-DB需要保持SSTable文件中键值对的顺序度以便提供更合理的范围查询性能。因此,一个针对性的compaction计划,可以有效合并SSTables,被集成到SLM-DB中。同时,为了保证B+树和LSM树的数据一致性,compaction的状态也应当被保存在PM中。

我们基于LevelDB 1.20实现了SLM-DB。我们继承了内存组件MemTale和Immutable MemTable的实现,仅修改了持久化到PM上这一块。我们保证SSTable文件格式的磁盘数据结构和和多SSTable文件compaction一样。我们也利用LSM树索引结构,包含有效SSTable文件,SSTable文件元数据,日志机制来记录所有针对LSM树的变更到MANIFEST文件,以及LevelDB的恢复机制。通过使用持久化的B+树,我们完全改变了LevelDB的随机读和范围查询机制。

在众多B树实现中,我们使用FAST和FAIR B树。因为保证所有键保序,FAST和FAIR B树被证明在范围查询上的性能,比其他B树要优秀。同时也可以获得最高的写带宽,通过利用内存级并发和内存保序指令。

3.1 持久化MemTable

在SLM-DB中,MemTable是一个持久化跳表。需要指明的是,持久化跳表已经有人研究过。跳表操作如插入,更新和删除可以被8byte原子操作完成。算法1展示了在最底层跳表中的插入操作。为了保证MemTable中键值对的数据一致性,我们先持久化一个新节点,并通过memory fence和cacheline flush指令持久化它的next指针。之后更新前序节点的next指针,8byte,并持久化。除了原地更新值,在MemTable中更新一个已经存在的键值对也是相似的方法。通过将MemTable驻留在PM中,SLM-DB不需要依赖WAL保证数据可靠性。类似的,也不需要为更高层的跳表提供数据一致性保证机制,因为可以从最底层很容易重构。

3.2 PM中的B+树索引

为了加速搜索存储在SSTable中的键值对,SLM-DB实现了B+树索引。当下刷Immutable MemTable中的键值对到SSTable中时,键同时也会被插入B+树。键被加入到B+树的叶子节点,这个叶子节点拥有一个指针指向PM对象,这个PM对象包含了键值对存储在磁盘上的位置信息。键的位置信息,包括SSTable文件ID,文件内block偏移和block大小。

如果键已经存在于B+树,一个新值回被写入SSTable中。因此,新的位置信息会被创建,并关联到对应B+树叶子接待你的指针,这些操作都是原子操作以防故障。如果删除标记插入,就从B+树删除键。位置信息的持久化内存的申请和释放通过持久化内存管理器如PMDK来管理,同时过期的位置对象会被垃圾回收掉。由于SLM-DB支持类似LevelDB中字符串类型的键,这种键会被转换为整数存入B+树。

构建B+树 在SLM-DB中,当Immutable MemTable刷入L0,其中的键值对会被插入B+树。对于一次下刷操作,SLM-DB创建了两个后台线程,一个创建一个插入。

在文件创建线程中,SLM-DB创建了一个新的SSTable文件并写入键值对到Immutable MemTable中。一旦文件创建线程下刷文件到磁盘,就添加所有已经存储在新创建的文件中的键值对到队列中,这个队列由B+树插入线程创建。B+树插入线程将队列中的键值对一个个插入B+树。一旦队列变空,插入线程就结束了。然后,LSM树相关变化会被追加到MANIFEST文件中作为日志。最终,SLM-DB删除Immutable MemTable。

扫描B+树 SLM-DB提供了一个迭代器,可以用来扫描全量键,类似LevelDB。迭代器支持seek,value和next操作。seek(k)操作定位迭代器到键为k的指定位置,如果k不存在,定位到不大于k的最大键位置。next()操作将迭代器移动到下一个键。value()操作返回当前迭代器指向的键的值。

在SLM-DB中,B+树迭代器被实现为扫描SSTable中的键。对于seek(k)操作,SLM-DB查询B+树中k的位置。在FAST+FAIR B+树中,键在叶子节点中排序,叶子节点也拥有兄弟指针。因此,如果k不存在,可以很容易的找到不大于k的最大键。同时,next()方法也可以通过移动迭代器到下一个叶子节点的键来完成。对于value()操作,迭代器查找位置信息并从SSTable中读取键值对。

3.3 选择性的compaction

SLM-DB支持选择性的compaction操作以便垃圾回收掉过期键值对和提升键值对在SSTable中的顺序程度。对于选择性的compaction,SLM-DB保存一个compaction SSTable文件备选列表。一个后台compaction线程会在SSTable文件组织变动的时候被调度,产生大量的seek操作。在SLM-DB中,当SSTable文件备选列表中,SSTable文件数量超过一定阈值,后台compaction线程也会被调度。当compaction线程执行的时候,SLM-DB选择一个SSTable子集作为下一次的集合。对于每一个SSTable,我们计算键在s和t之间的重叠比例,公式为\(MIN(s_p, t_q)-MAX(s_1, t_1) \over MAX(s_p, t_q)-MIN(s_1, t_1)\),其中键的范围\(s\)\(t\)分别是\([s_1,...s_p]\)\([t_1,...t_q]\)。注意到如果计算比例是负,\(s\)\(t\)就不存在重叠,比例会被设置为0.我们计算\(s\)的重叠比例总和。然后决定compact SSTable中拥有最大重叠比例的\(s^\prime\)。特别的,我们限制了同时合并的SSTable文件数量,以防严重影响前台用户操作。

compaction通过上述两个创建文件和插入B+树的线程来完成。然而,当合并多个SSTable文件的时候,我们需要检查每个键值对是合法的,还是过期的,这个可以通过查询B+树完成。如果是合法的,我们就把它和其它合法的进行合并排序。如果键不存在或正在其他SSTable中存储,我们就丢掉过期键值对而不是合并到新文件中。

compaction期间,文件创建线程需要创建多个SSTable文件而不是像下刷ImmuTable文件到\(L_0\)一样。文件创建线程会创建一个新的固定大小的SSTable文件,同时合并排序文件并下刷新文件到磁盘。之后将新文件中所有键值对加入B+树插入队列。之后开始新文件的创建,同时插入线程并发更新队列中的键值对到B+树。这一过程持续直到compaction完成。最终,在B+树更新所有新创建文件中的键值对完成之后,SSTable元数据的变化被提交到MANIFEST文件中,过期SSTable文件被删除。需要注意的是,SLM-DB中实现的B+树中插入的键值对,是在新文件创建之后立刻入列,并保序处理的。所以无需在更新B+树的时候,再次检查键的合法性。

为了选取compaction所需要的备用SSTable文件,SLM-DB实现了3种选择性的compaction算法,分别基于SSTable的live-key比例,B+树叶子节点扫描和每次范围查询的顺序度。基于live-key比例的选择,我们维护了一个合法键值对和所有键值对的比例。如果比例低于阈值,称之为live-key阈值,这意味着该SSTable拥有太多垃圾,就需要回收以便于更好的利用磁盘空间。对于每一个SSTable \(s\)\(s\)中存的所有键值对的总数在插入的时候就会被计算,同时最初的合法键值对数量等于总数。当键更新的时候,新键存储在新的SSTable中。因此,当我们更新B+树中指向新位置对象的指针的时候,我们也减去\(s\)中合法键值对的数量计数。基于这两个值,我们就可以计算每个SSTable中live-key比例。

计算live-key比例是为了优化磁盘空间,而基于B+树叶子节点扫描的算法,则是为了提升\(L_0\)中键值对的顺序度。不论后台compaction何时执行,先进行叶子节点扫描,具体是通过round-robin的方法依次扫描固定数量的叶子节点。扫描期间,我们计算这些被扫描到的键所在的SSTable文件的数量,重复文件仅计算一次。如果文件数大于阈值,称之为叶子节点阈值,就将这些文件加入到compaction备选列表。本文中,每次扫描叶子节点键的数量,基于两个因素决定,存储在单个SSTable文件中键的数量和每次扫描的SSTable文件数量。

对基于每次范围查询顺序度的选择算法来说,我们把一次请求键范围拆分城多个子范围。对于每个子范围,已经预设了一系列的键,我们保持跟踪独立文件的个数。一旦范围查询完成,就找到了子范围内拥有最多独立文件的个数。如果独立文件个数超过阈值,称之为顺序度阈值,我们就添加这些独立文件到compaction备选列表。这个功能在提升顺序度方面非常有用,尤其是如果请求符合Zipfian分布,也即一些键会被更加频繁的读取和扫描。

对于故障恢复,我们基本上添加了compaction备选列表,键值对总数和每个SSTable文件的有效键值对数到SSTable元数据中(通过日志存储在MANIFEST文件中)。在SLM-DB中,compaction和下刷操作更新B+树。因此,我们需要在PM中维护一个compaction操作的日志文件。在开始compaction或下刷操作之前,我们创建一个compaction日志。对每个已经存储在某些SSTable文件中的键,如果已经写入新文件,我们就添加一个数组包含老的SSTable文件ID到compaction日志中。同样的,为了compaction,我们需要跟进正在compaction的合并文件的列表。如果发生系统故障,已经更新的键和他们的旧文件IDs,这些信息会被用于恢复B+树和live-key比例。compaction和下刷完成以后,compaction日志会被删除。值得注意的是,通过叶子节点扫描或范围查询顺序度添加到compaction备选列表的一些SSTable文件记录,可能会在系统故障恢复之后丢失,原因是在系统故障之前没有写入MANIFEST文件。然而,丢失备选列表中的记录不会影响数据库的一致性。丢失的文件会被选择算法重新加入列表。

4 SLM-DB中的KV操作

Put 为了将一个键值对存入KV存储,SLM-DB插入键值对到MemTable。最终刷入\(L_0\)的SSTable中。键值对可能会被SLM-DB的compaction选择算法,通过compact写入新的SSTable文件中。
Get 为了获得给定k的值,SLM-DB依次查询MemTable和Immutable MemTable。如果k没有找到,继续在B+树中查找并定位到磁盘上的键值对(通过B+树指针指向的位置信息),读取相关值并返回。如果SLM-DB不能在B+树上找到k,就会返回结果而不读取任何磁盘上的block。
Range query 为了执行范围查询,SLM-DB使用B+树迭代器,通过seek操作,定位起始键位置,然后通过next和value操作扫描给定的范围并得到值。被插入SLM-DB的键值对,可以在MemTable,Immutable MemTable或\(L_0\)层的SSTable文件中找到。因此,对于seek和next操作的结果,需要和MemTable和Immutable MemTable中的迭代器操作的结果合并,作为最终结果,这一点很像LevelDB。
"Insert if not exists""Insert if exists": “没有才插入”,意思是如果查找没有键才会插入,而“存在才插入”则只更新存在的键,这些都是KV存储中常用的操作。更新负载,例如YCSB负载A通常执行已经存在的键才插入,如果键不存在就直接返回不插入键。为了支持这些操作,SLM-DB先在B+树上查询键是否存在。反之,大多数基于LSM树构建的KV存储,最坏情况下,必须在多层的多个SSTable文件中查询键是否存在。

5 故障恢复

SLM-DB提供了强大的故障恢复一致性保证机制,通过把内存数据存在PM中,磁盘数据存在SSTable文件中。对于最近插入MemTable的键值对,对比LevelDB,SLM-DB提供更强大的可用性和一致性。在LevelDB中,一些WAL数据不会强制下刷因为WAL下刷成本高昂,因此一些最近插入或更新的键值对可能会在系统故障中丢失。然而,SLM-DB中,跳表的最底层跳表保证8byte原子写入或更新到PM上,而不需要日志机制。因此,恢复流程中我们可以重建更高层的跳表。

为了利用LevelDB的恢复机制,SLM-DB添加了更多的信息到SSTable元数据中,例如compaction备选列表,每个SSTable文件的合法键值对数量和键值对总数。与原SSTable元数据一样,额外的信息通过日志存入MANIFEST文件。

当从失败中恢复,SLM-DB跟LevelDB一样,利用MANIFEST文件一样执行恢复流程。同时,类似于NoveLSM,SLM-DB依赖PM的支持如PMDK,重映射代表PM池的文件并恢复根数据结构,这些根数据结构存储了指向MemTable,Immutable MemTable和B+树的指针。SLM-DB也检查是否有进行中的compaction。如果有,SLM-DB必须将compaction日志中的文件重新进行compact。

对于下刷,SLM-DB使用已经更新的键和它的旧SSTable文件ID来保证每个SSTable文件上合法键值对数量的一致性。以compaction为例,可能上一次失败的compaction中,B+树叶子节点指向一部分键值对子集的指针已经提交指向新文件。然而,当系统重启,由于没有写入MANIFEST,这些文件不再合法。基于键和他们在旧SSTable文件中的ID,SLM-DB可以包括这些合法键值对并根据新的compaction更新B+树。由于PM硬件错误导致的数据损坏,可以通过校验和和数据复制来规避。

6 实验结果

6.1 方案

在我们的测试中,我们使用包括2个Intel Xeon Octa-core E5-2640V3的处理器(2.6GHz),和Intel SSD DC S3520(480GB)。我们关闭了一个socket,仅使用单个socket由8个核16GB内存组成。操作系统使用Ubuntu 18.04 LTS和4.15内核。

当同时运行LevelDB和SLM-DB的时候,我们通过内核参数限制内存到4GB。由于PM当前还没有在市场上提供,我们使用内存来模拟。我们配置了一个DAX使能ext4文件系统,同时部署PMDK为PM管理7GB内存池。默认设置中,写PM的时延是500ns(比DRAM高5倍)。PM写时延通过Time Stamp Counter来模拟,故意暂停一段固定的时延,并被应用于包含memory fence和cacheline flush的写命令中。读PM的时延没有额外增加。同时假设PM带宽和内存保持一致。

我们评估了SLM-DB的性能并比较了在不同值大小上的它的性能和LevelDB。对于所有的实验,关闭了数据压缩来简化分析和避免非预期现象出现。MemTable大小为64MB,键固定20byte大小。同时要指出,SSTable文件被存储在SSD上。对于LevelDB,除了MemTable的大小和使能布隆过滤器(10bit每个键),其他都是默认设置。在LevelDB所有实验中,为了更好的性能,不写WAL日志。对于SLM-DB,live-key阈值为0.7。如果提高这个阈值,SLM-DB会更频繁的执行垃圾回收。对于叶子节点扫描,我们扫描的键数量是两个SSTable文件中键数量的平均值,叶子节点阈值设置为10。值得注意的是,存储在SSTable文件中键数量的平均值,依赖值大小。对基于范围查询顺序读的选择算法来说,我们将一次范围查询拆分成30个键一次的子集,顺序度阈值被设置为8。如果我们提升叶子节点阈值和顺序度阈值,SLM-DB会执行更少的compaction。对于结果,每个平均值都运行了3遍。

为了评估SLM-DB的性能,我们使用db_bench工具作为微型性能测试,使用YCSB作为实际工作负载。性能测试通过单线程执行,这是因为LevelDB没有为多线程优化,我们在第7章会做解释。所有这些性能测试中,每次测试,会先进行8GB的随机写除非明确不需要,之后一共执行N次插入操作。其他每个负载执行20%写入操作。例如,如果执行10M写,会执行2M随机读操作。需要指出的是,为了创建数据库而随机写入的数据会少于8GB,因为某些键值对是重复的。

6.2 使用持久化的MemTable

为了理解使用PM驻留MemTable对的影响,我们首先调研了LevelDB的修改版本,LevelDB+PM的性能,它利用了PM来持久化MemTable而非WAL日志。图4展示了使用db_bench,在不同值大小的情况下,随机写在LevelDB,LevelDB+PM和SLM-DB下的性能。图4(a)和4(b),分别为写时延和根据LevelDB做归一化的数据写入磁盘总量。

在图中,通常来说,LevelDB+PM在写时延上更接近LevelDB,但是写入磁盘总量却减少了16%,这是因为没有WAL日志写入。当64KB,更大的值大小设置之后,LevelDB+PM的写时延降低了19%。LevelDB+PM同时也拥有更高的可靠性,这是因为数据写入MemTable会被持久化到PM中。对于SLM-DB,写时延和写入磁盘总量分别平均降低了49%和57%,和LevelDB相比。这是因为SLM-DB,通过组织单层SSTable文件和执行严格的compaction,更进一步降低了写放大。

图5展示了PM写时延对于SLM-DB写性能的影响。在这个图中,SLM-DB在PM上的写操作时延是300,500和900ns,图中展示了使用db_bench提供随机写负载,写时延归一化到SLM-DB的内存写时延的结果。在SLM-DB中,值大小1KB情况下,PM写时延越高,写性能就会降低75%。然而,随着值大小越来越大,PM写时延长尾影响会越来越小。

6.3 微性能测试的结果

图6展示了SKM-DB在随机写,随机读,范围查询和顺序写负载的情况下的带宽,均归一化到LevelDB对应带宽。在图中,展示在LevelDB柱子顶端的数字单位是KOps/s。范围查询负载扫描范围为100个键。对于顺序读负载,我们以升序方式顺序读KV存储中的所有键值对(数据集是随机写入的)。对于随机读,范围查询和顺序读负载,我们首先运行随机写负载插入数据到数据库,然后等待直到compaction流程完成,才进行对应的性能测试。

从结果中,我们可以发现如下结论:

  • 对于随机写,在不同值大小下,和LevelDB相比SLM-DB均提供了平均大概2倍的带宽。这是通过大幅度compaction写入磁盘的数据来实现的。注意到我们的实验中,插入B+树的开销很小,并且插入B+树是后台线程执行。因此,插入开销不会影响SLM-DB的写性能。
  • 对于随机读,SLM-DB在不同值大小下,和LevelDB相比都展示了相似或更好的性能。如章节2.2中讨论的,LevelDB的定位开销在值为1KB的时候不大。因此,SLM-DB在1KB值大小的情况下,只比LevelDB高7%。但是随着值大小递增,两者的性能差异增大,这是因为SLM-DB中的查询依赖B+树索引更有效率。然而,当值大小变为64KB,从磁盘读取block的时间占主要部分,所以两者的性能差异下降到25%。
  • 对于小范围查询,LevelDB每层都是的完全顺序的键值对,所以1KB和4KB值大小的性能更好。例如1KB值大小,一个4KB的数据block中包含4个键值对。因此当一个数据block因为读取操作被缓存在内存中,后续的3个顺序读请求就可以命中缓存。然而,为了定位到起始键,需要随机读,这里SLM-DB可以提供更高的性能。同时,对于更大的值大小,也需要花费更长的时间读取数据block。因此,即便顺序度稍低,SLM-DB也在范围查询里展现了差不多的性能。注意到扫描范围越长,SLM-DB的性能越好。例如,我们运行额外的测试,4KB值大小,1000个键的范围查询。在这个例子中,SLM-DB的带宽比LevelDB高57.7%。
  • 对于顺序读负载扫描所有键值对,SLM-DB除了在1KB值大小的测试中,其他都比LevelDB的性能要好。

在运行随机读,范围查询和顺序读负载的同时,也额外执行compaction操作。我们测量了LevelDB和SLM-DB从创建数据库到测试结束写入磁盘的数据量。通过有选择的compact SSTable文件,随机读,范围查询和顺序读测试中,SLM-DB平均写入磁盘的数据量只有LevelDB的39%。注意到LevelDB写入WAL的数据量是总写入量的14%。

为了垃圾回收,SLM-DB添加SSTable到compaction备选列表,挑选的条件是只有当SSTable文件中过期键值对超过一定比例,或者顺序度较差。我们分析了SLM-DB在db_bench的随机写负载中的空间放大。在多个值大小情况下,磁盘上数据量,SLM-DB比LevelDB多13%。最后,我们在表2中展示了SLM-DB的时延性能。

6.4 基于YCSB的结果

YCSB包括了6个负载,分别对应不同的实际场景。为了运行YCSB,我们修改了db_bench来测试不同的值大小。
图7(a),7(b)和7(c)展示了基于YCSB负载,SLM-DB的操作带宽,时延和总写入量,归一化到LevelDB,图中柱子顶端的数字是SLM-DB的,带宽单位是KOps/s,时延单位是ms/Op。对于每一个工作负载,都会在测试结束的时候统计写入总量。对于结果,我们通过插入键值对为工作负载A加载数据库,然后依次运行工作负载A,工作负载B,工作负载C,工作负载F和工作负载D。之后删除数据库并重载数据库来运行工作负载E。工作负载A执行50%读和50%更新,工作负载B执行95%读和5%更新,工作负载C执行100%读,工作负载F执行50%读和50%读改写。对于这些工作负载,都符合Zipfian分布。工作负载D执行95%的读最新的键和5%的插入。工作负载E执行95%的范围查询和5%的插入,也符合Zipfian分布。

图7(a)中,所有值大小中,SLM-DB的带宽都比LevelDB的带宽高,除了工作负载E在1KB值大小的情况下。对于4~64KB值大小,SLM-DB的性能在工作负载E下比LevelDB高15.6%,这是因为SLM-DB在范围查询中提供更好的点查询,以及compaction提供了比较高的顺序度。对于工作负载A,由50%读和50%更新组成,更新只在键存在的情况下生效。因此,这个更新是“insert if exists”操作。对于这个操作,SLM-DB能够更高效的在B+树上检查键是否存在。另一方面,LevelDB上检查键是否存在非常耗时。如果键不存在,LevelDB需要检查每一层。因此,对于工作负载A,SLM-DB平均比LevelDB高2.7倍的带宽。

正如图7(c)所示,SLM-DB的总写带宽,在所有的工作负载上,相比LevelDB都更小一些。尤其是1KB值大小情况下,对于工作负载D,SLM-DB只有LevelDB写磁盘数据量的13%。需要注意的是,YCSB所有工作负载中,LevelDB写WAL的比例是总写入量的11%。

6.5 其他性能因子

在之前的讨论中,我们主要聚焦SLM-DB如何在我们设想的为了典型KV存储设计的目标负载上测试。同样的,参数和计划选择也是SLM-DB设计的一部分。由于多种限制,我们无法在这些问题上做详尽的讨论。本章,我们会试图描述其中一些问题。

调节live-key比例的影响 在上述实验中,live-key的比例为0.7。当比例提高,SLM-DB将更频繁的做垃圾回收。我们执行了1KB值大小的随机写和范围查询负载,同时比例按照0.6,0.7和0.8变化。当比例为0.7的时候,相比于比例为0.6触发了更多的compaction,导致范围查询时延下降了8%,写时延上升17%。当比例为0.8,范围查询时延和比例为0.7的时候保持一致。然而,当比例为0.8,写性能会大幅度降低(比比例为0.6的性能降低2倍),因为live-key比例选择算法添加了太多的文件到备选列表中,导致SLM-DB阻塞在compaction中。和比例为0.6相比,0.7和0.8情况下,数据库大小分别下降了1.59%和3.05%,同时磁盘写数据量分别上升了7.5%和12.09%。

compaction备选算法的影响 基于叶子节点扫描和顺序度的选择算法,可以提高存储在磁盘上的键值对的顺序度。使用YCSB工作负载E,由大量的范围查询组成,在1KB值大小的设置下,我们分析了禁用这些算法对性能的影响。首先,同时禁用两种算法,时延会比同时打开两种算法高10倍。其次,仅禁用顺序度算法,这种算法仅会被范围查询触发。结果是范围查询时延上50%。最后,我们禁用叶子节点扫描算法同时打开顺序度选择算法。结果性能有15%左右的衰减。这表明,正如Sears和Ramakrishnan的研究所描述的那样,对于由单点查询,更新和偶尔的扫描组成的真实世界的负载,叶子节点扫描算法承担了重要的作用。

短范围查询 图8展示了在不同的键范围下,5,10,50和100,在SLM-DB中执行db_bench性能测试范围查询的结果,数据以LevelDB结果为准做归一化。对于小键范围,如5和10,性能结果在不同值大小的设置下,趋向于图6(b)中随机读负载所示结果,这是因为范围查询依赖随机读操作定位起始键。

更小的值大小 我们评估了128B值大小情况下,SLM-DB在db_bench的随机读写,范围查询工作负载下的性能。由于这个设置下,写操作的总数在范围查询中会变得非常大,由于资源和时间限制我们仅执行1%的写操作。对于这些实验,我们发现SLM-DB的写性能比LevelDB低36.22%。原因是PM写时延被设置为了500ns。当写时延和内存一致的时候,SLM-DB的写性能高出24.39%,写时延300ns的时候,仅比LevelDB低6.4%。在值大小比较小的情况下,我们看到了PM写时延对性能的影响。即便如此,特别要指出,由于LevelDB写WAL日志,打开fsync的性能比不打开慢了100倍,与之相比,SLM-DB提供了合理的写性能和数据高可靠性。对于随机读操作,SLM-DB提升了10.75%的性能。对于范围查询,当键范围在50和100的时候,SLM-DB的性能分别降低17.48%和10.6%。然而,键范围为5和10的时候,SLM-DB比LevelDB慢了3倍以上,这是因为LevelDB中键值对在磁盘上高度顺序存储导致缓存命中率很高。

LevelDB拥有额外的B+树索引 我们实现了一个版本的LevelDB,像SLM-DB一样通过PM存储B+树索引。这个版本利用B+树索引提高随机读性能,利用B+树迭代器提升范围查询性能。我们通过章节6.3中展示的,利用db_bench在不同值大小下,测试拥有B+树索引的LevelDB的性能。对于随机写负载,拥有B+树索引的LevelDB和不拥有的几乎性能一样。但是,对于随机读负载,其性能接近SLM-DB。对于范围查询负载,在各种值范围下,性能比LevelDB平均高6.64%,这是因为它不仅能利用LevelDB各层键值对的顺序性,同时也利用B+树迭代器替代各层迭代器。

PM带宽的影响 上述测试中,我们假设PM带宽和内存一致(8GB/s)。为了测试,我们使用了不同的机器,拥有2个Intel Xeon Octa-core E5-2620V4处理器(2.1GHz),通过热限流来降低内存带宽。SLM-DB的写性能同时受MemTable插入键值对和后台compaction的影响,compaction可以阻塞写。对于compaction来说,由于更低的PM带宽导致B+树插入性能下降大概为5%。然而,这对compaction的性能影响却几乎可以忽略,这是因为compaction的耗时主要在创建文件上。对于MemTable插入,相比于8GB/s内存带宽,2GB/s内存带宽的时候性能下降9%。因此,最终2GB/s带宽下的写性能大概比8GB/s带宽下的低6%。5GB/s的带宽下,MemTable插入性能没有受到影响,最后的写性能接近8GB/s带宽下的结果。我们也发现值大小发呢别为4,16,64KB的时候,SLM-DB的写性能不受PM带宽影响。

对于随机读负载,搜索MemTable和Immutable MemTable和搜索B+树的耗时,仅占整个读操作的0.27%带宽。因此,PM带宽在SLM-DB读测试上的影响可以忽略。特别的,在我们的实验中,PM和内存读时延被设置为一致。然而,我们相信这只会对最终的读时延造成微弱的影响,这是因为从PM上读数据的时延,相比于从磁盘上读数据的时延要小的多。

更大的数据库 我们评估了LevelDB和SLM-DB使用db_bench,在不同值大小的情况下,插入20GB数据创建数据库的性能。这些测试限制使用4GB内存。SLM-DB的写带宽和读带宽分别是LevelDB的2.48倍和1.34倍,范围查询带宽低10%。考虑到章节6.3中提到的8GB数据插入数据库的情况下,SLM-DB的写带宽和读带宽分别是LevelDB的1.96和1.45倍,范围查询带宽低11%。

7 讨论

PM损耗 SLM-DB利用PM持久化MemTable,Immutable MemTable,B+树和compaction日志。对于MemTable和ImmuTable MemTable来说,大小由用户设置且固定。B+树索引使用PM的量由其大小决定,数据库大小固定,值大小越小,记录越多,B+树索引就越大。最后,compaction日志同B+树索引相比,数据量很小。

在8GB数据库的测试中,MemTable和Immutable MemTable一共占用128MB空间。B+树,每个键在叶子节点占用26byte,8byte键,8byte指针,10byte存储位置信息。因此,需要多少PM空间完全由B+树叶子节点数量决定。特别的,1KB和64KB值大小,SLM-DB分别占用700MB和150MB的PM空间。PM成本应该比内存低,所以我们应该能够在获得KV存储更高性能的同时,保持一个比较合理的PM成本。

并发度 SLM-DB当前基于LevelDB修改实现。因此,LevelDB和SLM-DB都在多线程负载处理上存在限制。对于写,写队列限制写并发,对于读,需要在读取共享SSTable元数据之前加全局锁。但是,通过设计,SLM-DB可以很轻易的扩展来支持高并发;例如使用并发跳表替代当前实现,无锁化查询FAST和FAIR B树,多线程compaction。我们将SLM-DB支持并发作为未来的工作。

8 相关工作

已经有相关工作研究了KV存储利用PM。HiKV假设有一套混合PM和内存的内存系统,数据仅存在PM上。HiKV在PM上持久化了哈希索引来更高效的处理读和写,同时在内存中保存B+树支持范围查询。因此,系统故障恢复的时候,需要重建B+树。与HiKV不同,我们的系统考虑了PM和HDD和SSD共存,与之类似的是NoveLSM。与HiKV类似,SLM-DB也可以把B树索引放在内存中,哈希表索引放在PM中。但是,对于一个同时拥有PM和磁盘的混合系统,读时延不是很受影响,这是因为范围查询最终主要由磁盘性能影响,除非整个数据库可以完全缓存在内存。因此,在这样的混合设置中,即便需要付出一些保持两种结构的损耗,使用哈希表而不是B树索引也是值得的。pmemkv也是一个基于内存和PM混合的KV存储系统,存储B+树的非叶子节点在内存中,叶子节点在PM上。

NoveLSM和NVMRocks基于PM重新设计了LSM树。NoveLSM在磁盘数据,内存MemTable之间,提出了Immutable MemTable在PM上的设计,以此降低序列化和反序列化的损耗。另外,也有一个可变的持久化在PM上的MemTable,和内存MemTable一起用于降低compaction时的阻塞。由于内存MemTable+WAL日志和可变PM的MemTable一起使用,需要仔细处理内存MemTable的提交日志和键版本以确保数据一致性。当一个大型的可变PM MemTable被使用,大量的写被缓存在MemTable会导致Immutable MemTable下刷磁盘的频率降低。然而,为了处理一个比内存/PM存储的MemTable和Immutable MemTable总大小还大的数据库,数据必须存入磁盘。在NVMRocks中, MemTable被存储在PM中,跟SLM-DB一样消除了日志损耗,并且PM也像一个缓存用于提升读带宽。在NoveLSM和NVMRocks中,PM也被用于存储SSTable文件。然而,在我们的工作中,我们提出了将B+树索引持久化用于提升查询速度,提出了基于选择性compaction的单层SSTalbe文件,像LSM树一样利用了其内存组件。SLM-DB可以被扩展以便于利用大的PM存储的MemTable,多个Immutable MemTable和一个PM缓存,正交的提升KV存储的性能。

基于内存和磁盘来优化传统存储系统的LSM树的研究有很多。WiscKey提供了一种单独存放键和值到SSD中的技术。在WiscKey中,键被单独存放在LSM树中,而值类似LSM-DB一样,存放在单层日志文件中,以此来减少IO放大。由于解耦键值影响了范围查询的性能,该系统同时利用SSD的并行机制预读一部分数据来提升并发随机读性能。通过基于哈希函数聚合键值对,来优化垃圾回收性能以便应对更新频繁的负载。LOCS通过利用开放通道SSD来提升基于LSM树的KV存储。

VT树可以避免已经写入LSM树的数据重复写入,同时保证键值对顺序度,以此提供接近SLM-DB的范围查询性能。然而,VT树仍然需要获取多层上的键值对,并且没有关注提升读性能。LSM-trie系统关注降低写放大,特别是对拥有较小值大小的大范围KV存储。然而,LSM-trie系统由于构建在哈希函数上,不支持范围查询。PebblesDB提出了一种Fragmented Log-Structured Merge Tree,把键值对拆解成更小的文件,降低同层写放大。FloDB在MemTable之上引入了一种小型的内存buffer,对LSM树的内存结构进行了优化,从而更高效的支持偏向读写的工作负载。TRIAD也聚焦在这种负载上,通过把热键保存在内存中不下刷磁盘。引入分形索引树来降低基于B+树的系统的IO放大。

有多种研究,提供更合适的磁盘数据结构如radix树,哈希算法和PM上的B+树。这些优化写的同时也保证了PM上8byte原子写入的数据一致性。

9 重要结论

在这片论文中,我们展示了SLM-DB通过PM同时利用B+树和LSM树。SLM-DB利用一个持久化的B+树索引,PM驻留MemTable,和单层磁盘SSTable文件伴随选择性compaction。我们大量的实验研究表明SLM-DB提供了更高的读写带宽,以及和LevelDB相比不差的范围查询性能,并同时达成低写放大和接近理想极限的读放大。

鸣谢

略(都是针对相关人名的感谢)

引用

[1] Intel and micron produce breakthrough memory technology. https://newsroom.intel.com/news-releases/intel-and-micron-
produce-breakthrough-memory-technology/.
[2] Kyoto Cabinet: a straightforward implementation of DBM. http://fallabs.com/kyotocabinet/.
[3] Leveldb. https://github.com/google/leveldb.
[4] NVMRocks: RocksDB on Non-Volatile Memory Systems. http://istc-bigdata.org/index.php/nvmrocks-rocksdb-on-non-volatile-memory-systems/.
[5] pmem.io Persistent Memory Programming. https://pmem.io/.
[6] pmemkv. https://github.com/pmem/pmemkv.
[7] Recovery and Fault-Tolerance for Persistent Memory Pools Using Persistent Memory Development Kit (PMDK). https://software.intel.com/en-us/articles/recovery-and-fault-tolerance-for-persistent-memory-pools-using-persistent-memory.
[8] RocksDB. https://rocksdb.org/.
[9] YCSB on RocksDB. https://github.com/brianfrankcooper/YCSB/tree/master/rocksdb.
[10] BALMAU, O., DIDONA, D., GUERRAOUI, R., ZWAENEPOEL, W.,YUAN, H., ARORA, A., GUPTA, K., AND KONKA, P. TRIAD: Cre-ating Synergies Between Memory, Disk and Log in Log Structured
Key-Value Stores. In Proceedings of the 2017 USENIX Conferenceon Usenix Annual Technical Conference (USENIX ATC) (2017).
[11] BALMAU, O., GUERRAOUI, R., TRIGONAKIS, V., AND ZABLOTCHI, I. FloDB: Unlocking Memory in Persistent Key-Value Stores. In Proceedings of the 12th European Conference on Computer Systems (EuroSys) (2017).
[12] BEAVER, D., KUMAR, S., LI, H. C., SOBEL, J., AND VAJGEL, P.Finding a Needle in Haystack: Facebook’s Photo Storage. In Proceed-ings of the 9th USENIX Symposium on Operating Systems Design and Implementation (OSDI) (2010).
[13] BENDER, M. A., FARACH-COLTON, M., FINEMAN, J. T., FOGEL,Y. R., KUSZMAUL, B. C., AND NELSON, J. Cache-oblivious Stream-ing B-trees. In Proceedings of the 19th Annual ACM Symposium on Parallel Algorithms and Architectures (SPAA) (2007).
[14] CHAN, H. H. W., LI, Y., LEE, P. P. C., AND XU, Y. HashKV: Enabling Efficient Updates in KV Storage via Hashing. In Proceedings of the 2018 USENIX Conference on Usenix Annual Technical Confer-
ence (USENIX ATC) (2018).
[15] CHANG, F., DEAN, J., GHEMAWAT, S., HSIEH, W. C., WALLACH, D. A., BURROWS, M., CHANDRA, T., FIKES, A., AND GRUBER, R. E. Bigtable: A Distributed Storage System for Structured Data. In Proceedings of the 7th USENIX Symposium on Operating Systems Design and Implementation (OSDI) (2006).
[16] CHEN, S., AND JIN, Q. Persistent B+-trees in Non-volatile Main Memory. Proceedings of the VLDB Endowment 8, 7 (Feb. 2015), 786–797.
[17] COOPER, B. F., SILBERSTEIN, A., TAM, E., RAMAKRISHNAN, R., AND SEARS, R. Benchmarking Cloud Serving Systems with YCSB. In Proceedings of the 1st ACM Symposium on Cloud Computing (SoCC) (2010).
[18] DECANDIA, G., HASTORUN, D., JAMPANI, M., KAKULAPATI, G., LAKSHMAN, A., PILCHIN, A., SIVASUBRAMANIAN, S., VOSSHALL, P., AND VOGELS, W. Dynamo: Amazon’s Highly Available Key-value Store. In Proceedings of the 21st ACM SIGOPS Symposium on Operating Systems Principles (SOSP) (2007).
[19] DULLOOR, S. R., KUMAR, S., KESHAVAMURTHY, A., LANTZ, P., REDDY, D., SANKARAN, R., AND JACKSON, J. System Software for Persistent Memory. In Proceedings of the 9th European Conference on Computer Systems (EuroSys) (2014).
[20] EISENMAN, A., GARDNER, D., ABDELRAHMAN, I., AXBOE, J., DONG, S., HAZELWOOD, K., PETERSEN, C., CIDON, A., AND KATTI, S. Reducing DRAM Footprint with NVM in Facebook. In Proceedings of the 13th EuroSys Conference (EuroSys) (2018).
[21] HUAI, Y. Spin-Transfer Torque MRAM ( STT-MRAM ) : Challenges and Prospects. AAPPS bulletin 18, 6 (Dec. 2008), 33–40.
[22] HWANG, D., KIM, W.-H., WON, Y., AND NAM, B. Endurable Transient Inconsistency in Byte-Addressable Persistent B+-Tree. In Proceedings of the 16th Usenix Conference on File and Storage Technologies (FAST) (2018).
[23] KANNAN, S., BHAT, N., GAVRILOVSKA, A., ARPACI-DUSSEAU, A., AND ARPACI-DUSSEAU, R. Redesigning LSMs for Nonvolatile Memory with NoveLSM. In Proceedings of the 2018 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC) (2018).
[24] KANNAN, S., GAVRILOVSKA, A., GUPTA, V., AND SCHWAN, K.HeteroOS - OS design for heterogeneous memory management in datacenter. In Proceedings of the 2017 ACM/IEEE 44th Annual International Symposium on Computer Architecture (ISCA) (2017).
[25] KIM, H., SESHADRI, S., DICKEY, C. L., AND CHIU, L. Phase Change Memory in Enterprise Storage Systems: Silver Bullet or Snake Oil? ACM SIGOPS Operating Systems Review 48, 1 (May 2014), 82–89.
[26] KIM, W.-H., KIM, J., BAEK, W., NAM, B., AND WON, Y. NVWAL: Exploiting NVRAM in Write-Ahead Logging. In Proceedings of the 21th International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS) (2016).
[27] K ¨UAY, E., KANDEMIR, M., SIVASUBRAMANIAM, A., AND MUTLU, O. Evaluating STT-RAM as an energy-efficient main memory alternative. In Proceedings of the 2013 IEEE International Symposium on Performance Analysis of Systems and Software (ISPASS) (2013).
[28] LAKSHMAN, A., AND MALIK, P. Cassandra: A Decentralized Structured Storage System. ACM SIGOPS Operating Systems Review 44, 2 (Apr. 2010), 35–40.
[29] LEE, S. K., LIM, K. H., SONG, H., NAM, B., AND NOH, S. H. WORT: Write Optimal Radix Tree for Persistent Memory Storage Systems. In Proceedings of the 15th Usenix Conference on File and Storage Technologies (FAST) (2017).
[30] LU, L., PILLAI, T. S., ARPACI-DUSSEAU, A. C., AND ARPACIDUSSEAU, R. H. WiscKey: Separating Keys from Values in SSD conscious Storage. In Proceedings of the 14th Usenix Conference on File and Storage Technologies (FAST) (2016).
[31] MARMOL, L., SUNDARARAMAN, S., TALAGALA, N., AND RANGASWAMI, R. NVMKV: A Scalable, Lightweight, FTL-aware Key-Value Store. In Proceedings of the 2015 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC) (2015).
[32] MEI, F., CAO, Q., JIANG, H., AND TINTRI, L. T. LSM-tree Managed Storage for Large-scale Key-value Store. In Proceedings of the 2017 Symposium on Cloud Computing (SoCC) (2017).
[33] O’NEIL, P., CHENG, E., GAWLICK, D., AND O’NEIL, E. The Log-structured Merge-tree (LSM-tree). Acta Informatica 33, 4 (June 1996), 351–385.
[34] OUKID, I., LASPERAS, J., NICA, A., WILLHALM, T., AND LEHNER, W. FPTree: A Hybrid SCM-DRAM Persistent and Concurrent B-Tree for Storage Class Memory. In Proceedings of the 2016 International Conference on Management of Data (SIGMOD) (2016).
[35] RAJU, P., KADEKODI, R., CHIDAMBARAM, V., AND ABRAHAM, I. PebblesDB: Building Key-Value Stores Using Fragmented Log-Structured Merge Trees. In Proceedings of the 26th Symposium on Operating Systems Principles (SOSP) (2017).
[36] SEARS, R., AND RAMAKRISHNAN, R. bLSM: A General Purpose Log Structured Merge Tree. In Proceedings of the 2012 ACM SIGMOD International Conference on Management of Data (SIGMOD) (2012).
[37] SHETTY, P. J., SPILLANE, R. P., MALPANI, R. R., ANDREWS, B., SEYSTER, J., AND ZADOK, E. Building Workload-Independent Storage with VT-Trees. In Proceedings of the 11th USENIX Conference on File and Storage Technologies (FAST) (2013).
[38] WANG, P., SUN, G., JIANG, S., OUYANG, J., LIN, S., ZHANG, C., AND CONG, J. An Efficient Design and Implementation of LSM-tree Based Key-value Store on Open-channel SSD. In Proceedings of the 9th European Conference on Computer Systems (EuroSys) (2014).
[39] WONG, H. . P., RAOUX, S., KIM, S., LIANG, J., REIFENBERG, J. P., RAJENDRAN, B., ASHEGHI, M., AND GOODSON, K. E. Phase Change Memory. Proceedings of the IEEE 98, 12 (Dec 2010), 2201–2227.
[40] WU, X., XU, Y., SHAO, Z., AND JIANG, S. LSM-trie: An LSM-tree-based Ultra-large Key-value Store for Small Data. In Proceedings of the 2015 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC) (2015).
[41] XIA, F., JIANG, D., XIONG, J., AND SUN, N. HiKV: A Hybrid Index Key-Value Store for DRAM-NVM Memory Systems. In Proceedings of the 2017 USENIX Conference on Usenix Annual Technical Conference (USENIX ATC) (2017).
[42] YANG, J., WEI, Q., CHEN, C., WANG, C., YONG, K. L., AND HE, B. NV-Tree: Reducing Consistency Cost for NVM-based Single Level Systems. In Proceedings of the 13th USENIX Conference on File and Storage Technologies (FAST) (2015).
[43] ZUO, P., AND HUA, Y. A Write-Friendly and Cache-Optimized Hashing Scheme for Non-Volatile Memory Systems. IEEE Transactions on Parallel and Distributed Systems 29, 5 (May 2018), 985–998.

posted @ 2024-02-03 21:40  kiman  阅读(188)  评论(0)    收藏  举报