在 LSM 树 (Log-Structured Merge-Tree) 的设计中,读放大 (Read Amplification)、写放大 (Write Amplification) 和空间放大 (Space Amplification) 形成了一个类似 不可能三角 的权衡关系, 优化其中任意两个通常会恶化第三个; 这一现象类似于存储系统中的 RUM Conjecture (Read、Update、Memory overhead 不可能同时最优);

LSM-Tree 的放大问题

读放大

完成一次查询需要读取的数据量比实际所需数据多;
原因

  • 数据可能分布在多个SSTable中(MemTable + 多级SSTable),查询时需要检查多个文件。
  • 即使使用Bloom Filter减少无效IO,范围查询仍可能需要合并多个SSTable的结果。

优化方法

  • 增加Bloom Filter的精度,减少无效磁盘访问。
  • 使用分层Compaction(如Leveled Compaction),减少每层SSTable的重叠范围。

写放大

实际写入磁盘的数据量比用户写入的数据量大;
原因:LSM树通过后台 Compaction 合并 SSTable, 导致数据被反复重写 (例如: LevelDB 的 Leveled Compaction 可能产生 10 倍以上的写放大);

优化方法

  • 采用 Tiered Compaction (类似 Cassandra 的 STCS), 减少 Compaction 频率;
  • 使用增量压缩(如ZSTD)减少写入数据量。

空间放大

存储的冗余数据比实际有效数据多;
原因

  • 由于Compaction不是实时进行,同一份数据可能在多个SSTable中存在(未合并前)。
  • 删除操作只是标记(Tombstone),直到Compaction才真正清理。

优化方法

  • 更激进的Compaction策略(如Size-Tiered → Leveled)。
  • 尽早合并Tombstone,减少无效数据占用空间。

LSM-Tree 的不可能三角

优化目标 对其它放大的影响
降低读放大(如增加Bloom Filter、减少SSTable层级) ➔ 可能增加写放大(更频繁Compaction)或空间放大(更多未合并数据)
降低写放大(如减少Compaction频率) ➔ 可能增加读放大(更多SSTable需要检查)和空间放大(数据冗余更多)
降低空间放大(如更激进的Compaction) ➔ 可能增加写放大(更多数据重写)和读放大(Compaction占用IO带宽)

现实中的权衡案例

  • RocksDB(Leveled Compaction):优化读放大和空间放大,但写放大较高(适合读多场景)。
  • Cassandra(Size-Tiered Compaction, STCS):优化写放大,但读放大和空间放大较高(适合写多场景)。
  • WiscKey(KV分离):优化写放大和空间放大,但读放大增加(需额外查询Value日志)。

如何根据业务场景选择策略

业务需求 推荐优化方向 典型Compaction策略
低延迟读(OLTP、索引) 优化读放大 Leveled Compaction
高吞吐写入(日志、时序数据) 优化写放大 Tiered Compaction (STCS)
存储成本敏感(冷数据归档) 优化空间放大 定期Major Compaction + 压缩

优化

LSM树的 “三个放大” 问题确实是一个不可能三角,但通过合理的Compaction策略、索引优化(Bloom Filter、SSTable索引)和存储分层(Hot/Cold Tiering),可以在特定业务场景下取得较好的平衡。现代LSM引擎(如RocksDB)通过动态调整 Compaction 策略、使用 KV 分离(如WiscKey)等技术,正在不断逼近这个三角的更优解;