一文带你了解 LSM Compaction

做者:蚂蚁金服OceanBase数据库高级技术专家 华庭算法

当前,基于LSM架构的存储系统很常见,对该架构来讲,compaction(合并)是一个重要操做,本文带你了解compaction相关知识。

10年前Google发表BigTable的论文,推进了基于LSM的系统架构的流行,用户数据写入先写WAL,再写Memtable,知足必定条件后冻结Memtable,执行转储操做造成一个数据文件SSTable。随着数据写入不断增多,转储次数也会不断增多,进而转储SSTable也会愈来愈多。然而,太多SSTable会致使数据查询IO次数增多,所以后台尝试着不断对这些SSTable进行合并,这个合并过程称为Compaction。Compaction分为两类:Minor Compaction和Major Compaction。数据库

Minor Compaction是指选取一个或多个小的、相邻的转储SSTable与0个或多个Frozen Memtable,将它们合并成一个更大的SSTable。一次Minor Compaction的结果是更少而且更大的SSTable。缓存

Major Compaction是指将全部的转储SSTable和一个或多个Frozen Memtable合并成一个SSTable,这个过程会清理被删除的数据。通常状况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。                          markdown

compaction放大因子

一般Compaction涉及到三个放大因子,Compaction须要在三者之间作取舍。
架构

写放大

Write Amplification : 写放大,假设每秒写入10MB的数据,但观察到硬盘的写入是30MB/s,那么写放大就是3。写分为当即写和延迟写,好比redo log是当即写,传统基于B-Tree数据库刷脏页和LSM Compaction是延迟写。redo log使用direct IO写时至少以512字节对齐,假如log记录为100字节,磁盘须要写入512字节,写放大为5。性能

读放大

Read Amplification : 读放大,对应于一个简单query须要读取硬盘的次数。好比一个简单query读取了5个页面,发生了5次IO,那么读放大就是 5。假如B-Tree的非叶子节点都缓存在内存中,point read-amp 为1,一次磁盘读取就能够获取到Leaf Block;short range read-amp 为1~2,1~2次磁盘读取能够获取到所需的Leaf Block。测试

空间放大

Space Amplification : 空间放大,假设我须要存储10MB数据,但实际硬盘占用了30MB,那么空间放大就是3。有比较多的因素会影响空间放大,好比在Compaction过程当中须要临时存储空间,空间碎片,Block中有效数据的比例小,旧版本数据未及时删除等等。优化

最近几年不少论文对LSM写放大有比较多的研究,而对于写放大自己而言,是一个很古老的问题,在计算机体系中,若是相邻两层的处理单元不一致或者应用对一致性等有特殊的需求,就极可能出现写放大问题。好比CPU Cache和内存cell,文件系统Block和磁盘扇区,数据库Block和文件系统Block,数据库redo/undo,文件系统journal等。下图是PebblesDB论文中测试了几款流行KV的放大系数对比:spa

RocksDB放大系数高达42倍,LevelDB也高达27倍。写放大意味着更多的读写,会形成系统性能波动,好比对SSD来讲会加速寿命衰减,从成本角度说也更加耗电,采用更优的避免写放大的算法可使用成本更低廉的SSD,写放大还影响数据库系统的持续写入的带宽,假如磁盘带宽为500M/s,写放大为10,那么数据库持续写入的的最大带宽为50M/s,因此解决写放大就成了一个很重要的问题。设计

Facebook在Fast 14提交的论文《Analysis of HDFS Under HBase: A Facebook Messages Case Study》所提供的一些测试结论:在Facebook Messages业务系统中,业务读写比为99:1,而最终反映到磁盘中,读写比却变为了36:64。

放大问题的本质是一个系统对“随时全局有序"的需求有多么的强烈。所谓随时,就是任何的写入都不能致使系统无序;所谓全局,即系统内任意元单位之间都要保持有序。B-Tree系列是随时全局有序的典型表明,而Fractal Tree打破了全局的约束,容许局部无序,提高了随机写能力;LSM系列进一步打破了随时的约束,容许经过后台的Compaction来整理排序。在LSM这种依靠后台整理来保序的系统里面,系统对序的要求越强烈,写放大越严重。

要同时将写放大,读放大,空间放大优化到最优是很难的,好比SSD内部的碎片整理,碎片越多,空间放大和读放大越严重,为了改善空间放大和读放大,将page中的有效数据拷贝到新的page里(copy-out),这样会带来写放大,若是page中有效数据率越低,那么空间放大越大,copy-out的写放大越低,反之,空间放大越小,copy-out写放大越大。

compaction的做用与反作用

随着数据写入不断增长,Minor Freeze不断触发,转储数据不断增多,一次查询可能须要愈来愈多的IO操做,读取延时也在不断变大。而执行Minor Compaction会使得转储文件数基本稳定,进而IO Seek次数会比较稳定,延迟就会稳定在必定范围。然而,Minor Compaction操做重写文件会带来很大的带宽压力以及短期IO压力。所以能够认为,Minor Compaction就是使用短期的IO消耗以及带宽消耗换取后续查询的低延迟。

为了换取后续查询的低延迟,除了短期的读放大以外,Compaction对写入也会有很大的影响。当写请求很是多,致使不断触发Minor Compaction生成转储SSTable,屡次Minor Freeze会触发Major Freeze,从而致使Major Compaction,但Compaction的速度远远跟不上数据写入速度,Memtable内存不足时,会限制用户数据写入。若是Compaction消耗大量IO和带宽,也会致使读性能急剧降低。为了不这种状况,在Memtable内存紧张时候会限制写请求的速度。

Minor Compaction释放Memtable内存,清理没必要要的多版本数据,同时保证转储SSTable数量稳定,下降读延迟;Major Compaction清除删除和过时的数据,有效下降存储空间,也能够有效下降读取时延。Compaction会使得数据读取延迟一直比较平稳,但付出的代价是大量的读延迟毛刺和必定的写阻塞。

compaction目标

Compaction的设计老是会追求一个平衡点,一方面须要保证Compaction的基本效果,另外一方面又不会带来严重的IO压力。然而,并无一种设计策略可以适用于全部应用场景或全部数据集。Compaction选择什么样的策略须要根据不一样的业务场景、不一样数据集特征进行肯定。设计Compaction策略须要根据业务数据特色,目标就是下降各类放大,不断权衡以下几点:

合理控制读放大:避免因Minor Freeze增多致使读取时延出现明显增大,避免请求读取过多SSTable;

合理控制写放大:避免一次又一次地Compact相同的数据;

合理控制空间放大:避免让不须要的多版本数据,已经删除的数据和过时的数据长时间占据存储空间,避免在Compaction过程当中占用过多临时存储空间,及时释放已经Compact完成的无用SSTable的存储空间;

控制Compaction使用的资源:在业务高峰期少使用资源,业务低峰期使用更多的资源;

控制Compaction平滑度:在必定的负载下,业务的响应时间和吞吐量稳定可预期;

compaction算法演进

Memtable(增量数据) + L1(基线数据)

这是一种比较理想的场景,机器的内存比较大,磁盘空间和业务数据比较小,业务天天的修改几乎能够所有存储在Memtable中,采用每日Major Compaction的方式将增量数据与基线数据进行合并,以下图所示:


每张表包含一个增量数据Memtable和一个基线数据SSTable,这种每日Major Compaction算法比较简单,point read-amp为1,short range read-amp为1,空间放大为1,写放大为sizeof(database) / sizeof(memtable) + 1。这种Compaction算法保证最优读放大和空间放大,在Memtable内存比较大,磁盘空间和业务数据不大的状况下,写放大也能够接受,但随着业务数据量的增加,采用压缩率更高的压缩算法,以及单机存储空间的快速增加,写放大变得很是巨大,每日Major Compaction的速度变得愈来愈慢。

Memtable(增量数据)+L0(增量转储数据)+L1(基线数据)

随着业务的发展,每日更新的数据愈来愈大,Memtable已经不能存储成天的修改数据,当系统内存紧张时,触发Minor Freeze,而后转储生成SSTable,以下图所示:



point read-amp为>=1次磁盘读取和屡次bloomfilter过滤,short range read-amp为L0+L1 SSTable数量总和次磁盘读取,写放大为sizeof(database) / sizeof(每日增量数据量) + 2 (redo log,L0);最近几年单机的内存量几乎没有增长,但业务基线数据总量和天天的增量数据增加巨大,因此使用每日Major Compaction算法写放大很是大。随着L0层SSTable个数增长,读放大不断增长,为了限制L0层SSTable的个数,当转储达到必定次数后,发起一次Major Freeze,而后启动Major Compaction。这种策略会致使天天须要执行屡次Major Compaction,随着基线数据量的增加,写放大愈来愈大,Major Compaction也愈来愈慢。

根据场景选择Compaction策略

在不一样的场景如何折中选择读放大,写放大和空间放大呢?在系统中统一采用一种Compaction策略每每比较难兼顾各类细节需求,而针对不一样表配置不一样的Compaction策略能更好的适应表的读写负载。

递增rowkey的insert/update/delete,不管读写比例多少

最优写放大和空间放大,无读放大,采用Memtable + L1模式,若是delete range比较多,则在Memtable中标记delete range。

write only,大量随机rowkey insert/update/delete

优化写放大,采用Memtable + L0 + L1模式,每次转储生成一个SSTable,L0的总大小与L1相同时进行Major Compaction写放大最小。

write mostly,大量随机rowkey insert/update/delete

优化写放大,容忍稍大的读放大,采用Memtable + L0 + L1模式,L0层累积屡次Major Freeze的增量SSTable数据,L0层包含多个SSTable,按照优化写放大策略控制L0层SSTable数量和大小,使用Stripe Compaction和渐进合并策略减小Major Compaction的写放大和临时空间放大。

read only,或write不多

最优写放大,读放大和空间放大,采用Memtable + L1模式,Memtable没有数据或只有少许数据。

read mostly,少许随机rowkey insert/update/delete

优化读放大,采用Memtable + L0 + L1模式,每次转储Frozen Memtable与前一个L0层SSTable合并成一个新的L0层SSTable,若是delete range比较多,则在Memtable和L0层SSTable中标记delete range,L0与L1进行Major Compaction的写放大比较小。

read mostly,大量随机rowkey insert/update/delete

优化写放大和读放大,采用Memtable + L0 + L1模式,L0层累积屡次Major Freeze的增量SSTable数据,L0层包含多个SSTable,根据用户的访问热点决定哪些range内的L0层SSTable合并,若是delete range比较多,则在Memtable和L0层SSTable中标记delete range,将L0和L1分红多个sub-range条带,每一个sub-range积累了足够增量数据后才进行Major Compaction,相似渐进合并的方式,每次Major Freeze都合并L0和L1的部分range数据。若是delete比较多,空间放大不优,不能即便释放已经删除数据的存储空间。

相关文章
相关标签/搜索