跳到内容

5.2 Compaction、放大效应与 LSM 运维

新的有序文件不断堆进仓库,读取开始跨越越来越多层;后台整理若失控,又会抢走前台写入的带宽。

Compaction 不是“空闲时顺手整理”。它是 LSM 的持续核心工作:选择 overlapping sorted runs,merge 出新 files,丢弃已安全过期的 versions/tombstones,再原子安装新 version。它决定 steady-state write capacity、read latency 与 space usage。

Compaction 为什么必需

如果只 flush 不 compact:

  • files/runs 持续增加;
  • point lookup 与 range merge 检查更多来源;
  • tombstones 和 overwritten values 占用空间;
  • open files、metadata 与 cache 压力上升;
  • restart/recovery 与 backup enumeration 变重。

compaction 将“每次更新原地维护”的成本变成 background merge,但总成本仍要由设备吞吐和 CPU 承担。

Leveled compaction

典型 leveled layout:

text
L0: overlapping flush files
L1: sorted files, key ranges non-overlapping within level
L2: larger total target, non-overlapping within level
...

当某 level 超过 size/file target,picker 选择 input range,并把与下一层 overlap 的 files 一起 merge。优点通常是 lower-level point lookup 候选少、space amplification 可控;代价是 data 可能在 levels 间多次重写。

level size multiplier、file size、L0 triggers 都是配置策略,不是跨版本固定的“默认 10 倍、64 MB”。以当前 engine options 和 live metadata 为准。

Tiered / size-tiered / universal

这类策略允许多个 sorted runs 在同一 key space 共存,累计到 size/age/number 条件后合并。它通常减少重复搬运,适合偏写 workload,但读取要跨更多 runs,旧 versions 和 tombstones 也可能保留更久。

“tiered”不是所有产品共享的一套精确算法。Cassandra SizeTieredCompactionStrategy、RocksDB Universal Compaction 和其他 engines 的 selection/space rules 不同,不能把一个产品阈值套到另一个。

FIFO 与 time-window

TTL/time-series workload 可用 FIFO 或 time-window strategy,让整批过期 files 被删除,避免把必将过期的旧数据反复 merge。但只有当 query/time ordering、TTL 和 out-of-order writes 满足前提时才适用。

晚到数据、跨窗口 range query、更新旧 key 和 legal retention 都会改变设计。

三类 amplification

Write amplification

text
physical bytes written by storage stack / logical user bytes written

分子边界必须明确:只算 SST compaction、包括 WAL、包括 filesystem/device write amplification,数值会不同。compression 也可能让 physical bytes 小于 logical payload,却不代表没有 compaction CPU/reads。

Read amplification

可按 files/blocks/probes/bytes/IO operations 定义。point negative lookup、point positive lookup 与 range scan 的放大不同,不能用一个“层级数”覆盖所有请求。

Space amplification

text
physical live storage / logical latest live data

还要说明是否含 WAL、obsolete-but-not-deleted files、snapshots、tombstones、replicas 与 backups。只报 ratio 而不报 measurement scope 没有可比性。

这些目标互相制约,但不是固定三角公式。workload、compression、key distribution、retention 与 storage device 会改变 frontier。

Compaction debt 与 steady state

设 logical ingest 为 W bytes/s,average compaction write amplification 为 A,仅 compaction 写带宽需求数量级就是:

text
W × A

还未计 WAL、flush、reads 和 filesystem overhead。若设备可供 background 的持续吞吐低于需求,pending compaction bytes 会增长,最终进入 slowdown/stall。

burst 可由 memtable/L0 暂存,steady state 不能靠无限 backlog 维持。容量规划要看数小时/数天稳定窗口,不是只跑一分钟峰值 benchmark。

Write stall 是保护机制

常见触发:

  • immutable memtables 太多;
  • L0 file count/bytes 太高;
  • pending compaction bytes 超阈值;
  • WAL/space limit;
  • background threads/IO 跟不上。

slowdown/stall 保护 memory 与 read amplification,不只是“LSM 缺陷开关”。真正问题是为何 compaction capacity 低于 ingest:设备饱和、CPU compression、bad compaction config、oversized values、snapshot retention 或共享资源争用。

应用必须有 backpressure 与 deadline。无限 retry 会加重 stall。

Tombstone 与 snapshot retention

compaction 只有在能证明更旧 value 对所有相关 readers 不再可见时才可丢弃 tombstone。长期 snapshot、transaction、iterator、replication lag 或 backup pin 会延长保留。

症状:

  • logical delete 后 space 不降;
  • compaction read/write bytes 高;
  • point/range read 扫描大量旧 versions;
  • oldest snapshot age 持续上升。

删除大量 data 后立刻手动 full compaction 可能造成 I/O storm。先确认 retention blocker 和业务窗口,再选择 range/manual compaction。

Bloom 与 cache 不能替代 compaction

Bloom filter 能避免部分 negative point reads,却不能:

  • 移除 overwritten values;
  • 回收 tombstones;
  • 降低 range merge 的所有成本;
  • 减少 obsolete-file space;
  • 修复 compaction debt。

block cache 能隐藏部分 I/O,但 files/runs 过多仍消耗 metadata、CPU、iterators 和 cache space。

B+ tree 与 LSM 不是按“读多/写多”二选一

选型至少比较:

维度需要问的问题
writesustained/burst rate、update distribution、durability、value size
point readpositive/negative ratio、tail latency、cache budget
range readrange width、sort order、snapshot、merge sources
spacecompression、TTL、tombstone、temporary compaction headroom
consistencytransaction model、secondary indexes、constraints
operationsbackup、repair、upgrade、observability、stall behavior
hardwarelocal SSD、network block/object store、IOPS/bandwidth/endurance

B+ tree engine 也通过 WAL、buffering、group commit 和 sequential techniques 获得高 write throughput;LSM 也可以通过 filter/cache/compaction 获得好 read performance。最终必须用 representative workload 验证。

Operational metrics

通用指标:

text
logical write/read rate and latency percentiles
WAL bytes and sync latency
mutable/immutable memtable bytes/count
flush throughput and duration
files/bytes per level or run
pending compaction bytes/debt
compaction read/write bytes and CPU
write slowdown/stall duration
block cache hit by block type
Bloom useful/positive/false-positive counters
tombstone/obsolete versions and oldest snapshot age
disk free headroom and temporary compaction space

metric names随 engine/version 改变,要以当前官方 property/statistics 定义为准。单独看 estimate-pending-compaction-bytes 不等于 write amplification。

Benchmark 设计

  1. 数据量超过 memory cache,或明确报告 cache-resident test;
  2. 预填数据并等待/记录 compaction state;
  3. 使用真实 key/value size、update/insert/delete ratio;
  4. 同时运行 point/range reads 与 writes;
  5. 持续到 compaction steady state;
  6. 报告 p50/p95/p99、stall、physical bytes 与 space;
  7. 记录 engine/version/options/hardware;
  8. crash/reopen 后验证 durability 与 recovery time。

只比较“空库连续写一分钟”主要测 memtable/WAL burst,不足以比较存储结构长期能力。

安全变更顺序

  • 先确认 bottleneck 是 compaction,不是 application/OS/device 其他 workload;
  • 修改一个主要 option;
  • 保留足够 free space 完成最坏 compaction;
  • 限制 manual compaction 的 range/并发;
  • 观察 read tail latency 与 write stall guardrails;
  • 灰度到少量 shards/instances;
  • 保留 rollback,但注意某些 on-disk format option 不能无损回退。

本章小结

LSM 的优势来自 batching、immutable sorted runs 和后台 merge,代价则集中在 compaction debt、amplification 与 version retention。选型和调参不能只看“顺序写更快”,而要证明 steady-state ingest、read tail、space 和 recovery 同时满足目标。

官方资料入口

Built with VitePress | Software Systems Atlas