合并过程的算法是怎样的?
LSM-Tree(日志结构合并树)的核心是 “写时追加、后台合并”:数据先写入内存(MemTable),刷盘后形成 SST 文件,后台通过 Compaction 将小文件合并成大文件,同时清理删除 / 过期数据。
lsm-tree是有序的kv,合并很简单,把没用的key删了,把有用的key排序
TiDB LSM 合并核心是后台 Compaction:合并 SST 文件,清理无效数据,保持 KV 有序。
Compaction 策略:常见 Leveled Compaction(按层级合并)和 Size-Tiered Compaction(按大小分组合并),平衡读写性能与合并开销。
我感觉就是level0的immutable mem镜像,接下来就是分段排序合并,逐步进入freeze的最后阶段sst
TiDB是用的哪种合并策略?
TiDB的核心合并策略是基于Percolator优化的两阶段提交
-
配置参数参数
TiKV 内可使用compaction-style参数修改每个CF的compaction 算法:
可选值:“level”,“universal”,“fifo”
默认值:“level” -
算法介绍:
level:RocksDB的leveled compaction中 level 0包含有多个sorted-run,有多个sst文件,之间存在数据重叠,在compaction时将所有L0文件合并到L1层。对于L1-Lmax 层,每一层都是一个有序的Rorted-Run,包含有多个sst file。在进行读取时首先使用二分查找可能包含数据的文件,然后在文件内使用二分查找需要的数据。
Universal(tiered):Tiered 方式同样每层可以包含多个Sorted-Run ,Ln 层所有的数据向下合并到Ln+1层新的Sorted-Run,不需要读取Ln+1层原有的数据。Tiered方式能够最大的减少写放大,提升写入性能。
fifo:只有1层,写放大最小,每次compaction删除最老的文件,适合于带时间序列的数据。 -
详见:
lsm-tree是有序的kv,合并很简单,把没用的key删了,把有用的key排序
TiDB 的存储引擎 TiKV基于 LSM-Tree设计,其它的LSM 合并过程核心采用 分层级的归并排序 ,并结合 TiKV 自身的架构特点做了针对性优化
OcenaBase也是LSM结构,它是完全自己实现还是也用的RocksDB?
看了这篇博客,里面写RocksDB的leveled compaction中 level 0包含有多个sorted-run,有多个sst文件,之间存在数据重叠,在compaction时将所有L0文件合并到L1层。
有个疑问:这里的sorted-run是指把L0层的转储文件又重新生成了个排序文件的意思?
-
Leveled-N
和上面Classic Leveled 类似,不过每层可以有N个Rorted-Run,每层的数据不是完全有序的
这里的Rorted-Run是笔误还是就有这么个东西,看的太吃力了,不是很明白
网上搜了搜,应该是自己实现的。
1. Size-Tiered Compaction Strategy(STCS)( 上文中的Universal)
STCS(大小分层合并策略,亦称 Tiered Compaction)以优化写入性能为主要目标 。
工作原理:
- 初始阶段 :MemTable 刷盘后,生成一系列大小相近的小 SSTable 文件(如 64MB)。
- 触发合并 :当同层文件数量达到阈值(例如 4 个)时,触发合并。
- 合并过程 :该层所有文件被读入内存,进行多路归并排序,合并成一个新的、更大的 SSTable 文件。
- 层级晋升 :新文件晋升至下一层。当该层文件再次达到阈值时,继续向上合并,文件体积逐层倍增。
核心缺点:读放大高。
由于同层 SSTable 键范围重叠,点查询最坏需检查层内所有文件;范围查询则需合并多个文件的数据,开销更大。
2. Leveled Compaction Strategy(LCS)
LCS(分级合并策略)专注于优化读取性能和空间利用率 ,是 LevelDB/RocksDB 的默认策略。
数据组织:
- L0 层 :接收 MemTable 刷盘文件,允许键范围重叠。
- L1 及以上层 :每层内部 SSTable 的键范围严格不重叠 ,任一键最多只存在于该层的一个文件中。
优点:读取性能优秀。
点查询只需检查 L0 所有文件,并在 L1+ 的每层中快速定位唯一 可能的目标文件,读放大低。
缺点:写放大高。
数据从 L0 迁移至最高层的过程中,会在各级合并中被反复重写。
3. RocksDB 的混合策略:L0 层 Tiered,L1+ 层 Leveled
RocksDB 默认策略融合了 STCS 与 LCS 的优点 ,是一种经典且成功的混合方案。
- L0 层采用 Tiered 思想 :允许键范围重叠,作为写入缓冲。当文件数达到阈值时,才触发向 L1 的合并,能有效平滑写入峰值,避免写阻塞。
- L1 及以上层采用 Leveled 思想 :严格保持层内 SSTable 键范围不重叠,确保绝大多数数据的查询具有低读放大和高效率。
混合设计优势:
- 高写入吞吐量 :L0 层缓冲写入压力。
- 优秀读取性能 :L1+ 层结构保障查询效率。
- 可控空间放大 :继承了 LCS 在空间管理上的优势。
当 MemTable(内存表)被刷盘(Flush)时,或者在 Compaction 过程中,系统会先将数据分割成多个小的、局部有序的块(Block)。这些块被称为 Sorted Runs。
为了快速定位数据,SSTable 会在这些 Sorted Runs 的基础上构建索引结构。
最终,所有的 Sorted Runs 和索引信息被打包进一个不可变的文件中,这就是 SSTable。
lsm-tree算法,现在很多数据库使用此算法,比如:OCEANBASE,特点是写快,但存在多个版本后读性能变差,合并后改善
多谢,我再琢磨琢磨这里的细节!
是的,clickhouse也是用这个算法,对写入友好,需要做异步合并。