本节主要介绍分层转储的实现原理。
OceanBase 数据库的存储引擎采用 LSM-Tree 架构,数据大体上被分为 MEMTable 和 SSTable 两部分,当 MEMTable 的内存使用达到一定阈值时,就需要将 MEMTable 中的数据存储到磁盘上以释放内存空间,这个过程称为转储。在转储之前首先需要保证被转储的 MEMTable 不再进行新的数据写入,这个过程称为冻结(Minor Freeze),冻结会阻止当前活跃的 MEMTable 再有新的写入,同时会生成新的活跃 MEMTable。
分层转储
对于 OceanBase 数据库 V2.1.x 及之前的版本,在同一时刻仅会维护一个转储 SSTable,当 MEMTable 需要进行转储时,会将 MEMTable 中的数据和转储 SSTable 中的数据进行归并,这会带来一个问题,随着转储次数不断增多,转储 SSTable 的大小也越来越大,而一次转储需要操作的数据量也越来越多,导致转储速度越来越慢,进而导致 MEMTable 内存爆满。从 V2.2.x 版本开始,OceanBase 数据库引入了分层转储策略。
分层转储内部实现原理如下图所示。
OceanBase 数据库的转储分为以下三层:
L0 层
L0 层内部称为 Mini SSTable。根据不同参数设置的不同转储策略,L0 层的 SSTable 可能存在也可能为空。
对于 L0 层,系统提供了 Server 级的配置项来设置 L0 层内部分层数和每层最大的 SSTable 的个数。L0 层内部分为
level-0到level-n层,每层最大容纳的 SSTable 个数相同。当 L0 层level-n的 SSTable 到达一定数目上限或阈值后开始整体合并,合并成一个 SSTable 写入level-n+1 层。当 L0 层的最大 Level 内的 SSTable 个数达到上限后,开始做 L0 层到 L1 层的整体合并来释放空间。在存在 L0 层的转储策略下,冻结 MEMTable 直接转储在 L0-level-0 写入一个新的 Mini SSTable,L0 层每个 Level 内的多个 SSTable 根据 base_version 有序,后续本层或跨层合并时需要保持一个原则,参与合并的所有 SSTable 的 Version 必须邻接,这样新合并后的 SSTable 之间仍然能维持 Version 有序,简化后续读取合并逻辑。L0 层的内部分层会延缓到 L1 的合并,更好地降低写放大,但同时会带来读放大,假设共 n 层,每层最多 m 个 SSTable,则最差情况 L0 层会需要持有
(n * m + 2)个 SSTable,因此实际应用中层数和每层 SSTable 上限都需要控制在合理范围。L1 层
L1 层内部称为 Minor SSTable,L1 层的 Minor SSTable 仍然维持 Rowkey 有序,每当 L0 层的 Mini SSTable 达到合并阈值后,L1 层的 Minor SSTable 开始参与和 L0 层的合并; 为了尽可能提升 L1 合并的效率,降低整体写放大,OceanBase 数据库内部提供了写放大系数设置,当 L0 层的 Mini SSTable 总大小和 L1 层的 Minor SSTable 的大小比率达到指定阈值后,才开始调度 L1 合并,否则仍在 L0 层内部合并。
L2 层
L2 层是基线 Major SSTable,为了保证多副本间基线数据完全一致,日常转储过程中 Major SSTable 仍保持只读,不发生实际的合并动作。
转储触发方式
转储支持自动触发和手动触发两种方式。




