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

技术分享 | LSM-Tree 和 OceanBase 分层转储

767

作者:金长龙

爱可生测试工程师,负责DMP产品的测试工作

本文来源:原创投稿

* 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

先前在做 OB 存储引擎这块学习的时候,对 OceanBase 的分层转储和 SSTable这块有些细节就懵懵的,比如L0层的 mini SSTable 的每次生成是否就计入转储次数,L0层到L1层转储的时机以及和 minor_compact_trigger 之间的关系等。今天就这部分内容做个更细致的探究,试图更深入的理解 OceanBase 的分层转储。

一、LSM-Tree

首先来看一下 LSM-Tree(全称是 Log-Structured Merge Tree),当下许多较新的数据库都会选择 LSM-Tree 作为存储结构,比如 TiDB 、Cassandra 、OceanBase 等。LSM-Tree 的优势是顺序写,提升了整体写入性能。
LSM-Tree 大致可以分为两部分:
  • Memt
    able
    : 常驻内存的 KV 查找树  +
    无序的 WAL 文件
  • SS
    Table (Sorted Strin
    g Table)
    : 一组存储在磁盘的不可变文件,存储有序的键值对

写入流程

1、同步写 Memtable
先将数据写入 WAL 文件,然后修改内存中的 AVL,因此最优情况下,每次写操作只有一次磁盘 I/O。
删除操作并不会直接删除磁盘中的内容,而是将删除标记(tombstone)写入 Memtable 。当 Memtable 增大到一定程度后,则会转换为 Immutable Memtable 并产生一个新的 Memtable 接受写操作。
2、异步写 SSTable
后台会启动一个合并线程,当 Immutable Memtable 达到一定数量,合并线程会将其写入磁盘(Flush),生成 Level 0 的 SSTable 文件。
当 Level N 的 SSTable 文件数量到达阈值之后,会进行合并压缩(Compaction)操作,在 Level N+1 生成新的 SSTable 文件。
SSTable 分为多层,单个文件的大小通常是上一层的 10 倍,每层可以同时包含多个 sst file,每个文件由多个 block 组成,其大小约为 32K,是磁盘 IO 的基本单位。
第 Level i (i > 0) 层的 SSTable 满足:
  • 第 i 层所有文件均由 i - 1 层的 SSTable 合并排序而来,可以通过设定阈值(文件个数...)来控制合并的行为

  • 文件之间是有序的,且每个文件的 key 集合不会与其他文件有交集(Level 0 的 SSTable 除外)

Compaction 策略

常用的 Compaction 策略有 Classic Leveled、Tiered、Tiered & Leveled 、FIFO 等,简单介绍下前3种。

1、Classic Leveled
Classic Leveled 模式下每一层都是独立的"Sorted Run" ,代表是按 Key 排序且同层 sst file 之间的 Key 值没有重合,数量大小是逐层增大。相邻的两层 sst file 比称之为fanout(扇出),每次做 Compaction 的条件是Ln层大小达到了阈值,将Ln层数据与Ln+1层数据进行合并。由于每次做 Compaction 都将Ln层数据写入到Ln+1中,写放大情况会比较严重, 比如L1 ,L2 两层 fanout 是10,那么L1层写满后与L2层做排序合并,重写生成新的L2层,那么写放大最坏情况下等于 fanout
2、Tiered
Tiered 模式与 Classic Leveled 的区别在于每一层的sst file之间Key有重合的,每层有多个"Sorted Run",每次做 Compaction 都是同层先做合并生成一个新的 sst file 写入到下一层中,这里与 Leveled 最重要区别是写入到下一层后不再需要排序合并、重写,因为 Tiered 每层存在多个"Sorted Run",那么写放大最坏情况下为1。但是相比于 Leveled ,会有读放大和空间放大会比较严重。
3、Tiered & Leveled

Tiered & Leveled 模式是指对于层级较小的 Level ,数据量比较小,写入的数据较新,被更新的可能性比较大,使用 Size-Tiered 模式减少写放大问题;对于层级较大的 Level , SSTable 的数据量较大,数据比较旧不太容易被更新,使用 Leveled 模式减少空间放大问题。

二、OceanBase 的分层转储

OceanBase 数据库的存储引擎就是基于 LSM-Tree 架构的设计,也是划分为内存中的MemTable 和磁盘上的 SSTable 。OceanBase 将磁盘上的 SSTable 划分为三层,使用的是 Tiered & Leveled 的 Compaction 策略,在 L0 层使用 Tiered 模式,在 L1 层、L2 层使用 Leveled 模式。
OceanBase 中的 Compaction 分为三种类型:Mini Compaction 、Minor Compaction 、Major Compaction 。其中 Major Compaction 指的是大合并,我们先不谈,这里只说一下Mini Compaction和Minor Compaction

Mini Compaction (转储)

Mini Compaction 是一种 Tiered 类型的 Compaction,核心就是释放内存和数据日志,内存中的 Frozen MemTable 通过 Mini Compaction 变成磁盘上的 Mini SSTable。
Mini Compaction 在OceanBase设计里代表的就是一次转储,对应的类型是 MINI_MERGE

Minor Compaction

随着用户数据的写入,Mini SSTable 的数量会逐渐增多,在查询时需要访问的 SSTable 数量会增多,会影响查询的性能。Minor Compaction 就是将多个 Mini SSTable 合成一个,主要目的是减少 SSTable 的数量,减少读放大问题。当 Mini SSTable 的数量超过阈值时,后台会自动触发 Minor Compaction。
Minor Compaction 细分为两类:
1、L0 -> L0
Tiered 类型的 Compaction,将若干个 Mini SSTable 合成一个 Mini SSTable,放置于 L0 层。对应的类型是 MINI_MINOR_MERGE
2、L0 - > L1

Leveled 类型的 Compaction,将若干个 Mini SSTable 与 Minor SSTable 合成一个新的 Minor SSTable,放置于 L1 层。对应的类型是 MINOR_MERGE

实验(使用社区版 OceanBase 4.0.0.0)

测试创建的租户 ob_bench ,内存2G。几个主要参数设置为

memstore_limit_percentage = 50
freeze_trigger_percentage = 20
minor_compact_trigger = 2
_minor_compaction_amplification_factor = 25
major_compact_trigger = 9999  (我们本次实验仅是想>探索L0、L1级的Compaction,不希望触发大合并,所以该参数设置一个极大值)

实验一:在持续数据流的情况下,观测L0, L1层转储的时机

1、创建测试库 sysbench ,用 sysbench 工具创建1张表sbtest1、数据100W。

租户每触发一次转储 memtable dump flush 的数据必然是包含许多表的,我这里只创建1张业务表,仅是希望后续测试时业务变更相对集中

sysbench usr/share/sysbench/oltp_insert.lua --mysql-host=172.30.134.1 --mysql-db=sysbench  --mysql-port=2881 --mysql-user=root@ob_bench  --tables=1 --table_size=1000000 --report-interval=10 --db-driver=mysql --skip-trx=on --db-ps-mode=disable --create-secondary=off --mysql-ignore-errors=6002,6004,4012,2013,4016 --threads=10 --time=600  prepare

先通过视图 DBA_OB_TABLE_LOCATIONS 找到 sbtest1 对应的 TABLET_ID ,然后通过 GV$OB_TABLET_COMPACTION_HISTORY 查询到在创建100W数据过程中,已经触发了4次 MINI_MERGE 和1次 MINI_MINOR_MERGE

3、对 sbtest1 持续的写数据,观测 sbtest1 表级的转储情况

sysbench /usr/share/sysbench/oltp_insert.lua --mysql-host=172.30.134.1 --mysql-db=sysbench  --mysql-port=2881 --mysql-user=root@ob_bench  --tables=1 --table_size=1000000 --report-interval=10 --db-driver=mysql --skip-trx=on --db-ps-mode=disable --create-secondary=off --mysql-ignore-errors=6002,6004,4012,2013,4016 --threads=10 --time=600  run

测试总结:
官方对于参数 minor_compact_trigger 的解释:“minor_compact_trigger 用于控制分层转储触发向下一层下压的阈值。当该层的 Mini SSTable 总数达到设定的阈值时,所有 SSTable 都会被下压到下一层,组成新的 Minor SSTable 。”  https://www.oceanbase.com/docs/community-observer-cn-10000000000900778

如上测试时我们设置的 minor_compact_trigger = 2 ,按理解在每两次触发 MINI_MERGE 之后,就会触发一次 MINOR_MERGE ,把L0层的 SSTable 下压到L1层。实际测试下来发现未必如此,当达到 minor_compact_trigger 的阈值后,必然会触发 Minor Compaction ,但它可能是L0层上的 MINI_MINOR_MERGE(同层数据合并),也可能是L0->L1层的 MINOR_MERGE(数据下压到下一层)。但是具体什么情况下,触发哪种 Minor Compaction ,在官方文档只是介绍会受隐藏参数_minor_compaction_amplification_factor控制,但是具体如何影响的 也并没有给到相应的观测手法。

附:官网对参数 _minor_compaction_amplification_factor 的解释:“_minor_compaction_amplification_factor 控制 L0 层内部多个 Mini SSTable 转储的时机,默认为 25。当所有 Mini SSTable 的总行数达到 Minor SSTable 的写放大系数比例后,才会触发 L1 层转储,否则触发 L0 层转储。当 L1 层不存在 Minor SSTable  时,所有 Mini SSTable 行数到指定阈值(由 minor_compact_trigger 控制)后才会触发 L1 层转储。”

实验二:alter system minor freeze 是否真的在L1层做一个 MINOR_MERGE 类型的 compaction ?

1、同实验一的参数配置,且minor_compact_trigger = 2

先对sbtest1表记录做一次update,然后手动执行 alter system minor freeze ;(因为我们实验观测的是指定表的 merge 情况,所以在 minor freeze 之前要做一次 update 操作,主要是保证 memtable 中有对该表操作的记录)

如上我们看到,alter system minor freeze 之后只是做了一次 MINI_MERGE ,并没有到L1层。

我们再执行一次 alter system minor freeze ;

这一次我们发现在做了一次 MINI_MERGE 之后,触发了 MINI_MINOR_MERGE 。
我们可以继续这样做下去,最终我们发现 alter system minor freeze 实际上做的是 MINI_MERGE ,在 MINI_MERGE 之后具体是否会触发 MINI_MINOR_MERGE 或  MINOR_MERGE ,还是会受实验一里面所提到的参数 minor_compact_trigger 和  _minor_compaction_amplification_factor 的控制。
2、同实验一的参数配置,但设置 minor_compact_trigger = 0

同样是多次执行 alter system minor freeze ,每次执行后观察 merge 情况。

可以看到在 minor_compact_trigger = 0 时,当内存中的 memtable dump flush 到L0层后,会立刻下压到L1层, 这点同官方文档中的解释是一致的。
测试总结:

通过实验二的测试我们发现,alter system minor freeze 真正做的是形成一个 mini sstable (MINI_MERGE) ,在 MINI_MERGE 之后是否还会触发其他的 merge ,同样是受参数 minor_compact_trigger 和 _minor_compaction_amplification_factor 的控制。并且指令中的 minor freeze 实际上并不是特别准确,因为看到 minor 总会让人想到L1层,如果改成 mini freeze 会更合适一些。

参考资料
https://www.cnblogs.com/buttercup/p/12991585.html
https://www.modb.pro/db/608302
https://www.oceanbase.com/docs/community-developer-advance-0000000000634015
https://www.modb.pro/db/610025

https://ask.oceanbase.com/t/topic/31400011

本文关键字:#OceanBase# #分层转储#


文章推荐:

SQLE 二次开发环境搭建

SQL审核 | SQLE-SQL审核平台体验报告

MySQL binlog 分析工具 analysis_binlog 的使用介绍


关于SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取
类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs-cn/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs-cn/3.modules/3.7_auditplugin/auditplugin_development.html

更多关于 SQLE 的信息和交流,请加入官方QQ交流群:637150065...

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

评论