Compaction
LSM-Tree 的数据结构
由FE(调度者)调度,BE(执行者)执行,FE 以 Partition 为调度的基本单位,判断每个 Partition 的 Compaction Score 信息,进行优先级调度
查看 Partition 当前的 Compaction Score:
- AvgCS:当前 Partition 上所有 Tablet 平均 Compaction Score
- MaxCS: 当前 Partition 上所有 Tablet 最大 Compaction Score
SELECT * FROM information_schema.partitions_meta ORDER BY Max_CS DESC;
两个类型
- Cumulative Compaction(也称为 Segment/Merge Compaction)
- Base Compaction
Cumulative Compaction
概念:
-
负责处理 最新、最小的 Rowset。在 Size-tiered Compaction Strategy (STCS) 策略中,通常对应于对 L0 层(最新写入的、可能较小的 Rowset) 的合并。
Rowset:是一个逻辑概念,某个时间点写入/刷新到磁盘的一批数据,由一个或多个物理文件(Segment 文件)组成,有对应的元数据,通常是 RocksDB 或类似 KV 存储,在 BE 存储路径中能看到相关文件
作用:
- 快速合并最新写入的小文件: 将大量小而新的 Rowset 快速聚合成相对较大的 Rowset,减少文件碎片。
- 完成初步的数据去重/合并: 对于 Primary Key 模型,在数据量小、变化频繁的 L0 层及早进行数据的去重和合并,避免查询需要扫描大量历史版本。
- 将 L0 层的 Rowset 提升到下一层级 (Base 的候选): 为(Base)准备好更少、更大的 Rowset。
原理:
当系统检测到符合条件的 Rowset 时
- Rowset 选择: Compaction 调度器会扫描 Tablet 中所有处于 L0 状态(满足下面触发条件)的 Rowset。
- 读取数据: 读取被选中 Rowset 中的数据。这些 Rowset 尽管是新的,但可能由于多次写入/更新,包含同一行的多个版本。对读取进来的数据进行内部排序,合并,去重(Primary Key)
- 写入新 Rowset:将合并、去重后的数据写入到新的 Segment 文件,同时生成对应的索引文件和元数据文件,形成一个新的逻辑 Rowset(以五个1M的文件为例,最后合并成一个5M的文件)。
- 元数据更新:将参与合并的旧 Rowset 标记为过期
- 旧文件标记待回收:标记为过期的旧 Rowset 的物理文件最后被异步清理
Base Compaction
概念:
- 负责处理那些已经通过 Cumulative Compaction 优化过的、相对较大的 Rowset,再次合并
作用:
- 再次减少 Rowset 数量,整合层级: 将多个相对大、但仍属于不同版本层级的 Rowset 合并成一个或极少数几个更大的 Rowset
- 优化数据读取效率: 合并后的 Rowset 数据更加连续,可以减少查询时需要扫描的 Rowset 文件数量和寻道次数,提高查询性能。
- 最终形态的数据优化:Tablet 中数据的“最终形态”,包含去重、排序后的所有有效数据。
原理:
- Rowset 选择: 选择多个大小相似、并且能够满足合并条件的 Rowset 作为一个批次进行合并。在 Size-tiered Compaction Strategy (STCS) 下,Base Compaction 寻找的是多个 Rowset 之间的倍数关系,例如,合并几个比当前最大 Rowset 小一个数量级的所有 Rowset。
- 其他和 Cumulative 差不多
两个策略
- Size-tiered Compaction
- Update Compaction(Primary Key独有)
Size-tiered Compaction
核心思想:
-
将相似大小的 Rowset 合并成更大的 Rowset,然后这些更大的 Rowset 再去和同样大小的 Rowset 合并,以此类推
-
管理层级(默认7层):,将数据组织成不同的层级,每个层级都比之前的层级大一定倍数,每层的rowset数量达到一定阈值,向上合并
Update Compaction
去重、更新
项目实测
-
先写入数据到 MemTable ,达到阈值后会刷盘生成 rowset
-
触发条件(BE 配置)
-
MemTable 阈值:write_buffer_size(默认 104857600 Bytes)
-
猜测:事务提交完成了,即使未达到阈值,也会触发刷盘
-
-
-
Cumulative Compaction 快速合并大量的、新的、小的 rowset【数据可能重复】
- 默认触发条件(BE 配置)
- Segment 数量:min_cumulative_compaction_num_singleton_deltas(默认 5 个)
- 轮询的间隔:cumulative_compaction_check_interval_seconds(默认 1s)
- Size-tiered 策略下间接触发条件(BE 配置)
- 最小 Level 的大小:size_tiered_min_level_size(默认 131072 Bytes)
- 相邻两个 Level 之间相差的数据量的倍数:size_tiered_level_multiple(默认 5 倍)
- 【明细表】相邻两个 Level 之间相差的数据量的倍数:size_tiered_level_multiple_dupkey(默认 10 倍)
- 默认触发条件(BE 配置)
-
Base Compaction 合并成最终形态(一个超大的 rowset)【数据不重复】
- 默认触发条件(BE 配置)
- Cumulative 文件大小达到 Base 文件的比例:base_cumulative_delta_ratio(默认 0.3)
- Segment 数量:min_base_compaction_num_singleton_deltas(默认 5 个)
- 上一轮 Base 的时间间隔:base_compaction_interval_seconds_since_last_operation(默认 86400s)
- Base 线程轮询的间隔:base_compaction_check_interval_seconds(默认 60s)
- Size-tiered 策略下间接触发条件(BE 配置)
- 相邻两个 Level 之间相差的数据量的倍数:size_tiered_level_multiple(默认 5 倍)
- 【明细表】相邻两个 Level 之间相差的数据量的倍数:size_tiered_level_multiple_dupkey(默认 10 倍)
- 默认触发条件(BE 配置)
注意:Base 更容易触发,会跳过Cumulative
优化建议
-
控制 BE 上同时执行 Compaction 任务的线程数,默认值为4,也即 BE 上可同时为多少个 Tablet进行 Compaction
compact_threads = 4
-
单次 Compaction 任务最多合并的数据文件数量,默认为1000,在实践中我们建议将该值调整为100,这样,每个 Compaction Task 可以更快速地结束,且消耗更少的资源
max_cumulative_compaction_num_singleton_deltas=100
-
适当调整 Size-tiered 策略,最小 Level 的大小,两个 Level 之间相差的数据量的倍数,Level 数量
size_tiered_min_level_size
size_tiered_level_multiple
size_tiered_level_multiple_dupkey
size_tiered_level_num
修改BE配置:UPDATE information_schema.be_configs SET value = 8 WHERE name = “compact_threads”;