作者:金长龙
爱可生测试工程师,负责 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 大抵能够分为两局部:
- Memtable: 常驻内存的 KV 查找树 + 无序的 WAL 文件
- SSTable (Sorted String 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
2、先通过视图 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-10000000…
如上测试时咱们设置的 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-00…
https://www.modb.pro/db/610025
https://ask.oceanbase.com/t/topic/31400011