openGemini:Compaction流程解读

原创
2023/10/23 09:07
阅读数 25

openGemini Compaction流程解读

openGemini 存储引擎采用LSM结构,通过将所有的数据修改操作转换为追加写方式,通过这种方式将磁盘的随机写入转换为顺序写从而提高了写入性能,但是带来了以下问题:

  1. 大量的冗余和无效数据占用磁盘空间,造成空间放大。
  2. 读取数据时如果内存中没有的话,需要从L0层开始进行查找tssp file,造成读放大。

而解决上述问题主要是通过compaction操作将数据进行合并来降低空间放大以及读放大的影响。本文主要介绍OpenGemini的Compaction流程。

什么是Compaction?

Compaction是LSM Tree非常重要的操作,指的是把数据从Ln层,存储到Ln+1层这个过程,在这个过程中会将重复的旧的数据删除和数据重新排序,减少碎片化和提高读写性能。层级越高的文件,其所含数据越多,对应文件就越大。

Compaction过程

openGemini的Compaction主要针对有序数据,对于无序数据处理,参考上一篇文章openGemini如何高效处理乱序数据?

openGemini的Compaction操作整体过程如图所示,主要分为以下三个阶段:

第一阶段:数据写入

在数据写入过程中,当memtable达到一定数据阈值大小或到一定的定时周期后,将数据刷到immutable中。其中,有序数据写入到有序区域,乱序数据写入到乱序区域。

第二阶段:Level Compaction(同层级文件合并)

immutalbe中的数据刷盘后形成若干个L0层文件,L0层包含乱序数据文件,在图上未画出,乱序区域的文件会定时向有序区域文件中Merge,称为乱序合并。对于有序文件(例如L0_f1,L1_f1),按照每一层级指定文件数量进行合并(openGemini默认是8个L0层文件合并成一个L1层文件),此过程称为Level Compaction,合并原则为:低层级的文件合并频率高于高层级文件,优先合并最近落盘的文件。由于openGemini在写入过程中区分了有序乱序区域,且保证了每个文件内数据按sid(时间线ID)有序、每个sid对应的数据块按时间有序以及文件之间按时间有序。因此对于Compaction合并有序数据来说,可以采取高效的追加写,不需要进行额外的计算操作。

第三阶段:Full Compact(跨层级文件合并)

当openGemini遇到一段时间没有新数据写入时,将做一次Full Compact操作。

Full Compact是指跨所有层级的文件合并为一个最终的文件,如图上的未合并的L0_fn, L1_f5, L1_f6以及L2_f2和L2_f3这几个文件一起合并为L3_f1文件。这个过程中,若数据文件(比如L2_f1)已经达到一定阈值的时候(openGemini默认为8G),就不会参与Full Compaction,因为这样的文件对读性能不会再有大的增益。

在文件合并的过程中,假设L1层的4个文件L1_f1—L1_f4合并为L2_f1文件,如果全部文件加起来的大小为12G,超过8G阈值,则需要将文件进行切分为1个8G文件和一个4G的文件,4G的文件会在下次Compaction时被追加写入新合并的数据。openGemini对每个层级的文件都有设置大小限制,因此不太可能在L0层或者L1层出现非常大的文件。

compaction的两种方式

非流式compaction

非流式Compaction指把待合并文件中相同时间线的数据全部读取到内存中,重新排序合并后写入到新文件中。由于这种方式对内存资源有一定的消耗,稍不注意会有进程OOM的风险,因此对文件中时间线的数据大小进行约束,只有小数据量的情况采用该方法。

举个例子,如图所示,tssp1文件sid1和sid2对应chunk的大小都小于系统设定的预置,compaction会把tssp1和tssp2文件中sid1 chunk的所有segment读出来,重新排序(含对旧数据删除操作),再写入到新的tssp3文件中,新生成的文件保持与刷盘时的顺序原则保持一致。除L0层文件之外,通常tssp1和tssp2文件中的数据是不存时间交叉的,合并时仅需做追加即可。

对chunk和segment做一下解释。二者都是逻辑概念,openGemini的数据文件后缀名为tssp,每个数据文件在逻辑上被划分为若干个chunk(类似于插槽),每个chunk中保存的数据都属于同一个时间线,这些数据是按列进行组织,segment代表的是某一列固定行数的数据集合。

流式Compaction

流式compact指待合并文件中相同时间线的数据不是全部读取到内存中,每次仅读取一部分,合并后再读取,直到全部数据都已合并完成。主要针对时间线对应的数据量较大的情况,若全部读取到内存会造成大量内存占用,容易引起进程OOM。

举个例子,如图所示,tssp1文件中sid1待合并的chunk大小达到设定阈值时,此时将以单个segement为粒度读取数据,按列对多个文件相同sid的数据进行流式合并以及写入到新文件,直到所有sid对应的chunks都合并完成后,完成本次compaction流程。

Shard内数据文件布局

Compaction后台任务是以shard为单位并发进行的,单个shard内完成L0层Compaction后的目录及文件布局如下:

总结

本文主要介绍openGemini中LSM存储引擎的工作流程,openGemini通过定时Compaction来解决大量的冗余和无效数据占用磁盘空间以及减少读放大,合并原则为低层级的文件合并频率高于高层级文件,优先合并最近落盘的文件。希望可以帮助大家更好理解openGemini的数据存储实现。


openGemini官网:http://www.openGemini.org

openGemini开源地址:https://github.com/openGemini

openGemini公众号:

欢迎关注~ 诚邀你加入 openGemini 社区,共建、共治、共享未来!

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部