暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

LSM-tree 为什么会成为众多开源数据库的青睐

数据最前线 2023-08-19
143

说到LSM-tree,相信开源和国产数据库圈子的朋友对不会陌生,开源newSQL数据库CassandraRocksDBHBaseLevelDB,国产数据库TiDBOceanBase等都采用LSM-tree作为其底层存储引擎。LSM-tree何德何能,能够得到一众大小产品的拥簇呢?今天我们就来聊聊这个话题。

LSM-treeLog-Structured Merge Tree)是非常成熟且流行度非常高的数据库存储引擎,其设计思路来源于Google分布式“三驾马车”之一的论文《Bigtable: A Distributed Storage System for Structured Data》中所介绍的文件组织方式。

可以用一句话来概括LSM-tree卓越的写性能 一切均为顺序写。传统数据库的写出是日志顺序写加上数据随机写,而在LSM-tree中通过其精妙的架构设计将顺序写发挥到了极致,因而能够大幅提升数据库的写出性能。

一、基础架构

LSM-tree存储架构主要包含3个基础架构组件– MemTableSSTTableLogFile,整体架构如下图。

·MemTable是一种内存中的数据结构 -- 新的写入被插入到MemTable中,这部分数据是顺序写入到内存中的。当前MemTable写满时,会生成新的MemTable以接收后续的写入,同时当前MemTable被刷新到存储上以SST文件保存;

·写入MemTable的同时可选择性地写入日志文件,也称为预写日志(Write Ahead Log),同其他关系型数据库类似,日志文件也是按顺序写入和存储的。当数据库实例发生异常,可通过日志文件恢复还没有来得及持久化的数据;当其对应的MemTable数据被写出到SSTFile之后日志文件即可被安全的删除;

·SSTFileSorted String Table Files)是保存在物理存储上的持久化文件,用于保存写满的MemTable数据。如其名称所表达的那样,SSTFile中的数据也是按顺序存储的。

任何架构都是有得有失,LSM-tree也不例外,通过分层顺序写出的方式,可以将写入性能发挥到极致,但却有两个很致命的缺陷。

1)不同数据的查询和更新效率差异可能很大,如果查询的数据还在MemTable中,那么很快能获取到相应的数据,如果不在MemTable中,则需要逐层到SSTFile中进行查找,查询效率会明显下降;

2)空间消耗很大,由于其顺序写出机制的原因,SSTFile中的每一层都可能会存在大量重复数据,会浪费非常多的存储空间。

针对查询效率和空间浪费问题,LSM-tree引入了两个解决方案,数据压缩和查询优化。

二、数据压缩(Compact)

为了避免每一层SSTFile文件中包含过多的重复数据,LSM-tree引入了数据压缩机制,在向下合并的时候清理这些重复数据,并进行数据压缩,以提升空间使用效率。

1)Level Style Compaction,默认的压缩方式,每一层的大小由上至下指数增长,数据量达到指定大小开始压缩。该方式通过最小化每个压缩步骤中涉及的文件来优化磁盘占用空间与逻辑数据库大小(空间放大):将Ln中的一个文件与Ln+1中的所有重叠文件合并,并生成新的文件存放到Ln+1层。

2)Universal Style Compaction,也称为Tiered Compaction,与Apache Cassandra/ HBase使用的延迟压缩类似,当某层的runs/SSTables个数超出预设值或者数据库大小与最大一层的大小比值超过预设系数时才开始压缩,该方式通过一次合并潜在的多个文件和级别来优化写入磁盘的总字节数与逻辑数据库大小(写入放大),需要更多的临时空间。相比于级别压缩,通用压缩的写放大更低,但会导致更高的空间和读放大。

3)FIFO Compaction,一旦数据量达到预设值,将会丢弃旧数据并执行轻量级压缩,主要应用于内存缓存的场景。

不同的压缩策略对系统的整体影响不同,以下是三种主要的压缩策略对各项指标的影响对比。

通过调整压缩策略,能将LSM-tree配置成读友好、写友好、或者针对特殊缓存工作的极度写友好模式,开发者需要根据使用场景权衡指标配置。延迟压缩算法能够减少写放大、写吞吐,但是读性能会收到影响;而积极的压缩策略会影响写性能,但读效率会更高;日志与流处理服务可以使用侧重写,而数据库服务需要在读写之间做好平衡。

三、查询算法

数据压缩能够提升空间使用效率,使得数据查询时通过扫描更少的数据块就能够获取到需要的数据,从而提升查询效率。除此之外,数据库开发人员也通过引入Bloom Filter算法,来提升查询性能。

在任意的Keys集合中,应用一个算法并生成一个字节数组,这个字节数组就是Bloom Filter,对于任意一个Key,通过Bloom Filter可以得出两个结论:1)这个Key有可能在集合中;2)这个Key肯定不在集合中。

Bloom Filter在不同的数据库产品中有不同的实现,在RocksDB中,如果设置了Filter Policy,每个新创建的SSTFile都会包含一个Bloom Filter,这个Bloom Filter可以确定我们要查找的Key是否有可能包含在这个SSTFile中。

四、总结

通过上述的介绍我们可以看出,LSM-tree是一种优点和缺点同样明显的存储引擎,通过完全的顺序写来实现极致的写性能,但是由此又会带来查询效率的降低和空间使用上的膨胀。于是又通过数据压缩机制来提升空间使用效率,引入Bloom Filter来提升查询效率。

正应了那句老话,没有无缘无故的爱也没有无缘无故的恨。架构设计中也是这样,有所得必有所失,在某处获得了超额的收益,必然要付出额外的代价。优秀的产品总是通过合理的设计来放大自己的优点,尽量规避自身的缺陷;对于最终用户则需要充分了解产品的功能特性,选择最适合应用特点的产品。

文章转载自数据最前线,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论