1.如何用PM(NVM)优化LSM-Tree
2.论文导读 | 对于LSM Tree的码讲一系列优化工作
3.01| LevelDB架构分析
4.区块链存储技术选型之LSM-tree
5.LSM-tree 性能优化:Monkey, Dostoevsky
6.深入探讨LSM Compaction机制
如何用PM(NVM)优化LSM-Tree
LSM-Tree是适用于写密集型场景的存储结构,它利用顺序写入提高写性能。码讲然而,码讲随着大数据时代的码讲到来,B+Tree结构的码讲存储引擎逐渐显得不适应。LSM-Tree的码讲cf 辅助源码核心思想是将随机写转化为顺序写,从而提高系统性能。码讲以LevelDB为例,码讲它通过将数据追加写入LogFile,码讲并将其插入到内存中的码讲memtable中,实现了这种性能优化。码讲当memtable达到一定容量时,码讲数据被持久化到磁盘上的码讲SSTable,同时,码讲当需要删除数据时,码讲LSM-Tree会记录删除操作,直到合并操作真正执行删除。
非易失性内存(NVM或PM)被认为是下一代存储设备,它能够填补内存和SSD之间的性能差距,访问延迟接近内存,比现有闪存介质低1-2个数量级,并支持以字节单位寻址。NVM的单位容量价格虽然较高,但相对内存成本较低。这种技术的出现为优化LSM-Tree提供了新的可能性。
目前,已有几篇研究论文讨论了如何利用PM优化LSM-Tree。NoveLSM通过利用PM扩展memtable的容量,但其性能表现并不总是优于传统方法。SLM-DB在PM上同时使用了memtable和SSTable,并通过全局索引提高了查询效率,但在维护B+Tree方面存在代价。MatrixKV重新设计了LSM-Tree中的L0层,以利用PM的性能优势,减少写阻塞和写放大。Revisiting的策略是将数据存储在PM上,并在DRAM内建立索引,以减少DRAM使用并避免性能损失。ChameleonDB则专注于优化KV存储,采用了LSM-Tree结构并利用NVM提高点查性能。
总结这些工作,我们发现利用PM优化LSM-Tree的关键在于合理利用NVM的性能优势,通过设计优化数据存储结构和访问机制,提高系统的整体性能。不过,如何在不同场景下实现最佳性能,以及如何平衡NVM的高成本,仍然是一个值得深入探讨的问题。
论文导读 | 对于LSM Tree的一系列优化工作
LSM Tree,全称Log-Structured Merge Tree,是一种多级数据结构,以其快速更新和高效访存而受到广泛使用。产品推广app源码LSM Tree由多层有序数组组成,其中每一层的有序数组(Run)大小会随着层数成倍增加。LSM Tree有两种构造形式:Leveled和Tiered。在Leveled结构中,每一层只有一个Run,更新复杂度高但查询复杂度低;而在Tiered结构中,每一层存在多个Run,更新复杂度低但查询复杂度相对较高。Leveled结构通常采用合并策略,而Tiered结构则采用并行存储策略。在内存中,LSM Tree保留每一层数据的索引信息以提高访问效率,将所有Run划分成页并在内存中存储页的上线界和指针(FP),通过此方法可以一次访问SSD获得所需数据。此外,LSM Tree中的每个Run都建立了一个Bloom Filter(BF),用于判断查询元素是否存在于LSM Tree中,有效减少访问SSD的次数。
在SIGMOD 最佳论文中,提出了一种优化方法,旨在改善LSM Tree中Bloom Filter(BF)的性能。传统LSM Tree中的每个Run的BF大小与数组大小相匹配,以确保每个BF具有相同的假阳性率。然而,随着层数增长,每一层的大小成倍扩大,导致BF的大小也要成倍增加。在有限内存空间下,通过成倍降低假阳性率,可以在最高几层取消BF,实现更高效的内存使用和降低访存次数。
在SIGMOD 论文中,提出了一种平衡Leveled和Tiered结构优缺点的策略,称为Lazy Leveling。Lazy Leveling在前n-1层使用Tiered的合并策略,在最后一层使用Leveled的策略。这样,Lazy Leveling在点查询、大范围查询方面与Leveled结构具有相同的复杂度,但在小范围查询中性能优于Leveled结构,并且在合并操作中具有优势。与Tiered结构相比,除了合并操作外,Lazy Leveling的查询操作具有更低的复杂度。通过Lazy Leveling策略,可以实现更均衡的性能。
为了进一步优化LSM Tree性能,SIGMOD 论文中提出了一种流动的LSM Tree构造,通过引入两个参数K和Z来定义不同结构。K表示非最后一层中每层的有序列表数,Z表示最后一层的linux编译谷歌源码有序列表数,从而形成Leveled、Tiered、或Lazy Leveling结构。用户可以根据工作负载选择最合适的参数值,以获得最佳性能。
随着SSD性能的提升,LSM Tree内部数据访问不再是唯一瓶颈。为了应对查询时需要访问大量Bloom Filter的情况,论文提出了一种使用Cuckoo Filter(CF)的策略。Cuckoo Filter取代了传统Bloom Filter,通过存储元素所在Run的位置,将多个查询操作简化为一次访问,显著降低I/O复杂度。为降低CF的内存开销,论文提出了一种压缩方法,利用霍夫曼编码和组合编码策略,根据Run大小比例对指针进行编码,实现上层Run编码长、下层Run编码短的优化。同时,通过可变的指纹策略解决编码差异问题,实现CF的有效对齐。通过这些优化,LSM Tree的性能得到了显著提升。
| LevelDB架构分析
探索LevelDB的基石:LSM-Tree与高效性能
在分布式存储的世界里,LevelDB以其独特的LSM-Tree架构闻名,这款强大的键值存储系统在BigTable和HBase等项目中发挥着关键作用。LSM-Tree的核心理念是利用磁盘顺序写的优势,将随机写操作转化为顺序写,从而实现惊人的写性能提升。
LSM-Tree的设计巧妙地将数据结构划分为内存中的C0(小树)和磁盘上的C1(大树)层。写入操作首先记录在Write Ahead Log (WAL)中,随后添加至C0,当C0满时,会触发C0到C1的合并(Compaction),进一步优化存储。这种策略虽然牺牲了部分读性能,但换来的是更流畅的写入体验,尤其是在写多读少的场景下。 LevelDB的写入逻辑独特,新值优先且可能覆盖旧版本。MemTable,作为内存中的C0层,是数据的临时存储,当达到4MB阈值时,会转换为Immutable MemTable并生成SSTable(Sorted String Table)以持久化。这样的设计确保了写入的即时确认,即使遇到故障,也能通过日志恢复。 SSTable文件是LevelDB的核心存储格式,它们有序排列,公众号算命源码便于快速查找。Level-0 SSTable由于内存数据重叠,需要通过Compaction进行压缩,减少磁盘I/O和提高查找效率。而Level-i (i>0) SSTable则在文件数量达到一定阈值后触发压缩,进一步优化存储效率。 Compaction是LevelDB的灵魂,它负责合并多个SSTable为新的有序文件,同时删除旧的不再需要的数据。Leveled Compaction Strategy的策略确保了系统在内存和磁盘之间进行有效的数据平衡。Manifest文件记录了SSTable的版本编辑信息,包括新增和删除,这对于版本恢复至关重要。而Current文件则指示当前有效的Manifest,保持系统的完整性。 每次Compaction过程,都是对数据的一次整理和优化,通过按Key归并SSTable,将数据写入新文件,旧文件则被淘汰。这一系列操作的背后,是LevelDB对性能和可靠性的精心设计。深入解析LevelDB,我们将揭示更多关于其高效架构和优化策略的细节。
区块链存储技术选型之LSM-tree
LSM-tree,源于Google的BigTable论文,是一种在存储引擎中广泛应用的数据组织方式,如LevelDB、Cassandra、Hbase等。它的核心在于减少硬盘寻道开销,支持高效写入和删除操作。让我们通过对比B+树来理解LSM-tree的原理和特点。
B+树,如InnoDB中的实现,依赖于页的管理,每个页分配有唯一页号。数据插入时,会根据空间占用动态分配新页,B+树索引确保了查询性能的高效。然而,B+树对磁盘随机读写依赖较强,不适合HDD这类存储。
LSM-tree则不同,如LevelDB中的实现,写入流程包含写入LOG文件、内存数据库(MemTable)和定期的Minor Compaction。写入时直接写入内存,再持久化到硬盘,通过减少磁盘寻道来提升写入性能。它通过Major Compaction操作回收旧数据,文件搜索工具源码优化读取性能,但可能导致CPU资源消耗增加。
比如Wisckey的优化,针对LSM-tree的写放大问题提出了KV分离策略,通过将大值数据写入单独的ValueLog,减小LSM-tree的大小,从而降低写放大和提升读取性能。读取时,根据key直接在内存或level 0的sstable中查找,如果值为ValuePointer,则进一步获取实际值。
总的来说,B+树和LSM-tree各有优劣,B+树适用于读多写少的场景,LSM-tree在处理大量写入和减少寻道开销方面更具优势。RocksDB等存储引擎在LSM-tree基础上进行了优化,以适应更复杂的性能需求。
LSM-tree 性能优化:Monkey, Dostoevsky
最近探讨了两篇关于LSM-tree性能优化的文章,下面简要总结。
文章重点集中在两个优化策略上:Monkey和Dostoevsky。
Monkey的主要改进点在于优化point lookup操作的开销。通过调整不同层LSM-tree中Bloomfilter的内存大小,即调整假阳性率,以降低point lookup的开销。直观地理解,业界的LSM-tree实现中,各层假阳性率相同,导致较大层内存需求较多,而较小层的内存性价比更高。因此,Monkey通过数学论证得出,通过使LSM-tree中从下到上的Bloomfilter假阳性率指数递增,可以实现最优的开销优化。优化后,无论是Leveled还是Tired方案,不管是zero-point lookup还是point lookup到现有条目的操作,开销均有所降低。
Dostoevsky则提出了一种折衷策略,通过平衡Leveled和Tired两种方案,牺牲部分短范围lookup性能,以换取更好的update性能,适用于写密集型场景。
结合Monkey和Dostoevsky的策略,LSM-tree最终的时间空间复杂度得到优化。文章最后对这两个方法的效果进行了总结:Monkey通过调整不同层的Bloomfilter假阳性率,实现了在不增加update开销的情况下降低lookup开销的优化;而Dostoevsky通过优化update性能,虽然牺牲了部分lookup性能,但在特定场景下提供了更好的性能体验。
深入探讨LSM Compaction机制
深入探讨LSM Compaction机制
compaction在LSM-Tree架构系统中是核心模块,通过周期性后台任务优化读性能和空间问题。它通过回收旧版本数据和合并数据层次来提升系统效率。然而,compaction策略和任务调度成为新难题,需平衡空间、I/O、CPU资源和缓存等多方面因素。
compaction策略主要作用在于数据的GC与归并排序。策略约束LSM-Tree结构,决定合并哪些文件、任务大小和触发条件。不同的策略影响读写放大、空间放大和临时空间大小。系统通常支持多种策略并配备多个调整参数,以适应不同应用需求。
读放大描述每次读请求带来的读盘次数,写放大则是每写1byte数据导致n bytes的数据写入,写放大体现序要求与整体平衡。LSM-Tree系统中,compaction策略优化写放大。空间放大关注所占空间与实际数据量比值。传统数据库忽视空间放大,而随着SSD为主流存储介质,节省成本成为重要考量。
临时空间是compaction任务运行时所需,任务结束旧数据才能删除。粒度控制临时空间大小。sstable为有序字符串表,不同系统使用不同名称,核心含义相似。大小控制是策略中关键要素。
Size-tired策略适合高写入负载,写放大较低,但读放大和空间放大较高。图示SCylla中所示,memtable周期刷盘到sstable,形成层内多个有序运行。层级数据达限制后合并并flush至下一层,循环直至数据量未达限制。
缺点:空间放大和读放大明显。Leveled策略能减小空间放大和读放大。LSM-Tree由多层组成,每层大小维持前一层次T倍。当相邻层次大小相同值时,写放大最小。Leveled策略中,每个层由多个sstable组成有序运行。当数据量达上限,与下一层运行合并。这种方式减少了读放大和空间放大,小sstable提供精细化任务拆分条件。
Hybrid策略结合了Tiered和Leveled,能在读写放大、空间放大之间取得平衡。Leveled-N策略优化写放大,允许每层有多个有序运行。Dostoevsky中提出的lazy compaction思想,通过调整最大层运行数量和相邻层大小比来平衡读写放大和空间放大。
时间序列数据特点如下,针对这些特点引入特定compaction策略以提升性能。每个sstable有开始和结束时间标记,选择sstable时考虑时间范围,相似范围的sstable逐渐合并。老的sstable时间范围更大,几乎没有时间范围交叠。这种策略应对特定时间过滤查询时有效。
每个系统围绕“how and when”选择策略和调度机制,不同目标导向系统采用不同策略。偏向写优化的系统如Bigtable、Hbase、Canssdr,偏向空间优化和读优化的系统如RocksDB。RocksDB支持多种compaction机制,包括经典Tiered和Leveled,还提供了优化写放大的Leveled-N和Hybrid方式。
SCylla支持Tired、Leveled compaction策略,默认为Size-tired,面向写优化场景。引入增量compaction(IC)优化临时空间放大问题。Time-window compaction(TWCS)是Date-Tired的替代版本,针对时间序列优化读性能。
Hbase的compaction类型分为minor和major,适用于不同场景。minor选择部分store files合并,数据量少而频繁,不回收多版本数据。major合并所有store files,涉及大量数据,一般长时间才会触发,主要处理过期数据。
compaction任务执行对性能显著影响,主要表现在消耗资源和导致cache失效。任务运行时的压缩、拷贝和比较消耗CPU资源,读写数据消耗I/O资源。cache失效引起性能降低。
学术研究在分布式KV store中使用offload compaction到单独服务器和增量缓存回填来解决资源消耗和cache失效问题。在Hbase架构中,增加compaction manager和compaction server组件,将compaction任务offload到compaction server,并使用远程缓存增量预热本地缓存,优化读性能。
分布式场景下通过外部方式解决compaction问题,如smart cache等,利用远程内存保存新数据,渐进式替换本地缓存,确保读请求的一致性,提高性能。
LSM Tree的改良结构FLSM通过减少重写来减小写放大,使用FLSM构建高性能KV store,PebblesDB。FLSM通过引入guard将数据分隔,减少compaction过程中的重写,加快compaction速度,但影响读性能。优化策略如Seek-Based Compaction和Parallel Seeks减少读开销。
Dostoevsky论文详细分析不同操作在Tired和Leveled策略下的I/O复杂度,提出优化策略lazying leveling,动态计算最优配置以达到最大吞吐,实现Fluid LSM。论文深入探讨compaction机制复杂性,指出通用机制优化worst-case的局限性,系统需适应多种场景。
compaction代价在单机中不可避免,策略选择优化worst-case成为研究方向。大多数系统支持多种compaction实现,通过适配多种参数满足不同业务需求。分布式场景依赖调度策略优化资源需求,这一话题更为复杂。
实际应用中,业务负载不会持续让系统处于worst-case,选择适应性策略优化系统平稳状态。引入调度控制,根据负载曲线调度不同任务以满足不同时期资源需求。这一方向上的研究和探索有助于提升LSM-Tree系统性能和适应复杂场景。
剖析lsm 索引原理
剖析lsm 索引原理
lsm 更像是一种设计索引的思想,它将数据分为内存与磁盘两部分存储。内存数据采用高效的数据结构如红黑树、跳表进行检索。当内存数据达到阀值时,同步至新磁盘文件,磁盘写入顺序进行,提高写入性能。
解决并发读写问题,当内存区域满载时,标记为只读,新数据写入新区域,旧区域同步至磁盘,不加锁。每次同步生成新文件,引发数据合并。查找时,从多个文件读取合并最新数据,避免了b+tree原地合并。
数据在内存中有序,写入磁盘时保持有序,形成sstable文件。为解决sstable文件重叠导致的查询效率问题,通过合并不同文件,使得每个文件间索引范围不重叠,加快数据检索速度。
合并策略采用多层次方式,每一层容量是上一层的倍,有效减少磁盘I/O,缓解写放大问题。只有当新增sstable与当前层文件有重合时,才进行合并,减少频繁全量合并带来的磁盘压力。
总结,lsm在写入时先内存后磁盘,内存采用高效数据结构提升读写性能,通过合并多层文件优化查询效率。读取数据时,先从内存读取,若不足则逐层查找,利用文件顺序与合并后的不重叠索引范围提高检索速度。
与b+tree对比,b+tree更新时需加锁,避免随机写入问题,但随机读性能好。lsm则在高效写入的同时,面临读放大问题,查询集中在最近数据时性能较好。
剖析lsm原理后,理解了其数据管理与索引优化机制。日常中,运用自问自答的方式深入理解问题,是有效学习和掌握技术的关键。
LevelDB 源码剖析1 -- 原理
LSM-Tree,全称Log-Structured Merge Tree,被广泛应用于数据库系统中,如HBase、Cassandra、LevelDB和SQLite,甚至MongoDB 3.0也引入了可选的LSM-Tree引擎。这种数据结构旨在提供优于传统B+树或ISAM(Indexed Sequential Access Method)方法的写入吞吐量,通过避免随机的本地更新操作实现。
LSM-Tree的核心思想基于磁盘性能的特性:随机访问速度远低于顺序访问,三个数量级的差距。因此,简单地将数据附加至文件尾部(日志或堆文件策略)可以提供接近理论极限的写入吞吐量。尽管这种方法足够简单且性能良好,但它有一个明显的缺点:从日志中随机读取数据需要花费更多时间,因为需要按时间顺序从近及远扫描日志直至找到所需键。因此,日志策略仅适用于简单的数据访问场景。
为了应对更复杂的读取需求,如基于键的搜索、范围搜索等,LSM-Tree引入了一种改进策略,通过创建一系列排序文件来存储数据,每次写入都会生成一个新的文件,同时保留了日志系统优秀的写性能。在读取数据时,系统会检查所有文件,并定期合并文件以减少文件数量,从而提高读取性能。
在LSM-Tree的基本算法中,写入数据按照顺序保存到一组较小的排序文件中。每个文件代表了一段时间内的数据变更,且在写入前进行排序。内存表作为写入数据的缓冲区,用于保持键值的顺序。当内存表填满后,已排序的数据刷新到磁盘上的新文件。系统会周期性地执行合并操作,选择一些文件进行合并,以减少文件数量和删除冗余数据,同时维持读取性能。
读取数据时,系统首先检查内存缓冲区,若未找到目标键,则以反向时间顺序检查各个文件,直到找到目标键。合并操作通过定期将文件合并在一起,控制文件数量和读取性能,即使文件数量增加,读取性能仍可保持在可接受范围内。通过使用内存中保存的页索引,可以优化读取操作,尤其是在文件末尾保留索引块,这通常比直接二进制搜索更高效。
为了减少读取操作时访问的文件数量,新实现采用了分级合并(Leveled Compaction),即基于级别的文件合并策略。这不仅减少了最坏情况下需要访问的文件数量,还减少了单次压缩的副作用,同时提供更好的读取性能。分级合并与基本合并的主要区别在于文件合并的策略,这使得工作负载扩展合并的影响更高效,同时减少总空间需求。