TOS 2021 Paper 论文阅读笔记整理
问题
持久的键值存储已经成为现代数据处理系统的数据访问路径中的一个主要组件。然而,它们表现出较高的CPU和I/O开销。
基于LSM Tree的键值存储中两个重要的CPU和I/O开销来源是:
-
在LSM Tree中使用压缩,不断执行大型数据段的合并和排序,产生CPU和I/O开销。
-
使用缓存避免I/O访问设备,但驻留在内存中的缓存数据也会产生大量CPU开销,占总CPU开销的28%。
随着新硬件的出现,在队列深度32时,I/O请求大小为32KB达到了SSD的最大吞吐量,I/O请求大小为8KB时达到了NVMe的最大吞吐量。因此,由于I/O放大而增加的流量成为比I/O随机性更重要的瓶颈。
本文方法
本文提出了Kreon,针对基于闪存的键值存储,利用I/O随机性换取低CPU开销和低I/O放大。
-
使用细粒度溢出机制,利用部分重组而不是使用每个级别的完整索引来进行完整的数据重组,提供高插入率并减少CPU开销和I/O流量。使用按N个级别组织的写优化数据结构,类似于LSM树,其中每个级别充当下一个级别的缓冲区。为了减少I/O放大,不对已排序的缓冲区进行操作,而是在每个级别中维护一个B树索引。因此,它生成较小的I/O请求,但减少I/O放大和CPU开销。
-
使用内存映射I/O来执行内存和设备之间的所有I/O。内存映射I/O本质上用内存映射取代了缓存查找,消除了内存中数据项的开销。未命中会导致页面错误,直接从内存执行I/O操作,而无需在用户和内核空间之间复制数据。然而,内存映射I/O的异步特性意味着I/O发生在页面粒度上,从而导致许多小I/O,尤其是对于读取操作。此外,内存映射I/O不能提供任何类型的一致性、可恢复性,也不能根据特定需要调整I/O。为此,本文实现了一个自定义的内存映射I/O路径kmmap作为Linux内核模块,消除了在内核和用户空间中使用DRAM缓存的需要,消除了内核和用户之间的数据拷贝,并消除了指针转换的需要。
-
键值存储通常同时为本地(同一节点)和远程(网络)客户端提供服务。本文为远程客户端实现了基于RDMA的远程直接内存访问协议。
在大型数据集中,与RocksDB相比,Kreon将CPU周期/op减少了5.8倍,将插入的I/O放大减少了4.61倍,并将插入操作次数增加了5.3倍。
总结
针对在SATA SSD和NVMe SSD上的LSM Tree优化问题,随机I/O不再是性能瓶颈,CPU和I/O开销限制LSM Tree的性能。本文提出Kreon,针对基于闪存的键值存储,利用I/O随机性换取低CPU开销和低I/O放大。(1)采用和LSM Tree类似结构,但每层内用B Tree组织,因此层间合并时只需部分合并,不需要对整个SSTable进行合并,从而降低I/O放大和CPU开销,但引入了更多小的随机I/O。(2)使用内存映射执行内存和设备之间的所有I/O,用内存映射取代了缓存查找,消除缓存开销和数据复制。但会导致许多小I/O,且不能提供任何类型的一致性、可恢复性。为此,本文实现了内存映射I/O路径kmmap,消除了在内核和用户空间中使用DRAM缓存,消除了内核和用户之间的数据拷贝,并消除了指针转换。