Skip to content

Http Command Manual Compaction

rockeet edited this page Sep 8, 2023 · 34 revisions

1. Command 概览

curl 'http://somehost:port/db/dbname?html=0&compact=default'

该 Http 命令调用了 CompactRange 函数,所以该 Http 命令的参数主要是 CompactRange 的参数。

2. Http 参数

compact 参数是必不可少的,其它参数,实践中一般仅会用到 max_compaction_bytes 和 max_subcompactions

参数名 参数类型 默认值 说明
compact string 指定 ColumnFamily
max_compaction_bytes int64 0 每个 compact 任务的最大字节数
max_subcompactions int 1 每个 compact 任务的子任务数量
exclusive_manual_compaction bool false 如果为 true, 不能同时执行其它 compact
allow_write_stall bool false 如果为 true, 即便该 compact 会引发 write stall, 也立即执行;如果为 false, 会等到系统不忙时再执行 compact
change_level bool false 如果为 true, 并且 change_level > 0, compact 输出的 sst 将被移动到 target_level
target_level int -1 仅在 change_level 为 true 时有效
target_path_id int 0 如果为 sst 配置了多个 path, 该参数指定 compact 输出的 sst 放置的 path id
bottommost_level_compaction enum kIfHaveCompactionFilter enum 类型为 BottommostLevelCompaction

3. 参数详解

3.1. max_subcompactions

CompactRange 是通过多个 compact 任务完成的,这些 compact 任务是一个接一个串行执行的,不是并发执行的,所以很慢。

我们给上游 RocksDB 提过并发执行的 Feature Request,但至今仍未被实现

虽然多个 compact 任务不能并发,但每个 compact 任务可以切分成多个子任务,多个子任务可以并发,该参数指定每个 compact 任务的子任务数量。

在分布式 compact 中,是以 compact 任务为单位调度的,单个 compact 任务的多个子任务只能调度到一个 compact 计算结点,所以该参数无法利用多个 compact 计算结点并行计算。

3.2. max_compaction_bytes

该参数不是 CompactRange 的参数,而是 ColumnFamilyOptions 的成员,通过 db.SetOptions(cf, optionMap) 来修改,从而会导致其它 compact 也受影响。

如果该参数非 0,就调用 SetOptions 修改,等 CompactRange 结束后恢复原值;如果该参数为 0,就不会调用 SetOptions。

3.3. bottommost_level_compaction

该参数一般很少使用,在此列出其 enum 定义

enum BottommostLevelCompaction {
  // Skip bottommost level compaction
  kSkip,
  // Only compact bottommost level if there is a compaction filter
  // This is the default option
  kIfHaveCompactionFilter,
  // Always compact bottommost level
  kForce,
  // Always compact bottommost level but in bottommost level avoid
  // double-compacting files created in the same compaction
  kForceOptimized
};

4. 现实问题

在实践中,要快速地执行 compact,最好同时设置 max_subcompactions 和 max_compaction_bytes 两个参数,例如:

curl 'http://hostname:port/db/dbname?html=0&compact=default&max_compaction_bytes=10G&max_subcompactions=23'

如果增大 max_subcompactions 时不增大 max_compaction_bytes,会导致两个问题:

  • 产生大量尺寸很小的 sst 文件
  • compact 任务的创建和 compact 结果的安装,其相对耗时占比会较大,可能会占到 20% 甚至更多

而如果将 max_compaction_bytes 设置得过大,又会导致另外两个问题:

  • 内存和外存空间占用:新 sst 安装到 LSM 中并且旧 sst 不再被引用之后,才能删除旧的 sst 文件,在这期间内,新旧 sst 同时存在,占用双倍内存和 SSD 空间
  • 一次安装过多 sst 文件,会对 db 的在线服务造成较大抖动,安装新 sst,新 sst 预热的短时间内,CPU 消耗和内存的换入换出会导致系统的负载剧烈抖动,影响在线服务

5. 代替方案

Manual Compact 无法并发,但是自动 Compact 可以并发,利用这一点,我们可以尝试主动触发自动 Compact:

curl -d '{"cfo":{"cfname":"max_bytes_for_level_base=50M"}}' 'http://somehost:port/db/dbname?html=0&indent=2'

把 max_bytes_for_level_base 改到很小会触发自动 compact,自动 compact 可以跑满 max_background_compaction 设置的并发。compact 完成之后要手动把该参数改回旧值。

在分布式 compact 加持下,可以把 Compact 任务调度到多个 Compact 计算结点上,从而快速完成全量 compact。

注意:max_bytes_for_level_base 不宜设置得过小(极端值是设为 1),否则会导致触发 hard/soft_pending_compaction_bytes_limit,进而 write stall 甚至 write stop。

注意:这个方法虽然提高了并发,但是增加了计算量,Manual Compact 是从顶层到底层一层一层 Compact 的,而这个方法是所有层同时 Compact,从而下层的一部分 Compact 会发生在上层 compact 之前,从而相比 Manual Compact 多了一些工作量(直接的指标就是写放大升高)。