Compaction 经验总结

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 倍)
  • 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 倍)

注意: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”;

3赞

新手总结的经验,有不对的地方,欢迎指出,彼此共进

1赞