文章目录
LSM Tree 结构

Memtable
Memtable 是一种内存中的有序数据结构,Memtable 在 RAM 内存层面,它存储数据是有序的,当我们向 LSM Tree 中写入数据之前,会先将数据顺序写入到 MemTable 内存中,一旦 MemTable 内存的数据量达到预设的阈值,或者到了预定的时间间隔,其中的数据便会被刷新(Flush)并整理成 SSTable。
但是数据在写入 MemTable 内存中保存,这必然会有持久化方面顾虑,担心数据会丢失,所以 MemTable 采用了 WAL 机制,先将日志写入到磁盘,然后变更 MemTable。也就是先顺序写到日志当中,这样就是为了防止断电导致 Memtable 内存中的数据丢失,跟 MySQL Redolog 的思想是相似的。记录下发生的每一项操作,以防系统发生故障。
当 Memtable 存储达到阈值后,它会被转换成 Immutable Memtable,不再接收新的写入;新的写入进入新的 Memtable,而后台线程再将 Immutable Memtable Flush 成 SSTable。
SSTable
SSTable 是一种持久化、有序且基于磁盘的键值数据结构,主要用于维护数据的顺序与一致性。Memtable 刷写到磁盘的数据量不断增加,生成的 SSTables 数量也会随之增多。
随着时间的推移,SSTables 的数量会不断增加,系统会生成更多层级的 SSTable,其中数据会变成旧数据、脏数据、重复的数据...所以 LSM Tree 会执行 Compaction 合并操作优化存储空间的利用效率。在分层的 LSM Tree 实现中,越往下的层级通常容量越大,数据会通过 Compaction 被持续合并和重写,以减少重复、过期和删除标记带来的影响。

查询流程
在进行数据查找时,LSM 树首先会查询 Memtable,访问存储在内存(RAM)中的数据性能非常快,如果无法检索导数据,就会开始查询 SSTable。
SSTable 属于磁盘存储结构,查找可能会相当缓慢。为了解决这一问题,SSTable 维护了布隆过滤器(Bloom Filter),该结构能够在读取数据时显著加速查找过程。如果所需数据没有在 Memtable 中找到,LSM 树便会查询布隆过滤器,以核实该数据是否存在于某个的 SSTable 之中。
如果布隆过滤器提示数据可能存在于 SSTable 中,便会利用该 SSTable 的索引块对其进行查找。如果布隆过滤器显示数据肯定不存在,LSM Tree 便会跳过该 SSTable,转而对下一个 SSTable 进行查找。
新增流程
在进行数据新增时,LSM 树并不会直接将数据写入磁盘中的 SSTable,而是会先将数据写入 WAL(Write Ahead Log)日志文件中。这样做的目的是为了防止数据只写入内存、但还未来得及落盘时系统发生故障,从而导致数据丢失。
在 WAL 写入完成之后,数据会被写入 Memtable。由于 Memtable 是位于内存中的有序数据结构,因此写入速度非常快。当 Memtable 中的数据量达到预设阈值后,它会被转换成 Immutable Memtable,随后由后台线程将其中的数据刷新(Flush)到磁盘中,生成新的 SSTable。先写 WAL 保证持久性,再写 Memtable 提高写入性能,最后再批量刷盘生成 SSTable。
修改流程
在进行数据修改时,LSM 树通常不会直接在原有的数据位置上进行更新,而是会将这次修改视为一条新的写入操作。系统会先将这次修改操作写入 WAL,以保证在宕机或断电的情况下,仍然可以通过日志恢复数据。
修改后的新数据会被写入 Memtable 中。由于 LSM Tree 不会立即删除或覆盖磁盘中旧版本的数据,因此相同 key 可能会在不同的 Memtable 或 SSTable 中同时存在多个版本。查询数据时,系统会按照从新到旧的顺序进行查找,因此最终读取到的会是最新版本的数据。
当 Memtable 刷盘生成新的 SSTable 后,旧版本的数据依然可能暂时保留在更早生成的 SSTable 中,直到后续执行 Compaction 时,旧版本数据才会被逐步清理。LSM Tree 的修改流程本质上并不是原地更新,而是写入一个新版本的数据,并通过后续 Compaction 清理旧版本。
删除流程
在进行数据删除时,LSM 树通常也不会立即将磁盘中的数据物理删除,而是会先写入一条特殊的删除标记,这个标记通常被称为 Tombstone。系统同样会先将删除操作写入 WAL,以确保删除操作具备持久化能力。
在 WAL 写入成功之后,LSM 树会将该 key 对应的 Tombstone 写入 Memtable 中。之后随着 Memtable 刷盘,这条删除标记也会被写入到 SSTable 中。此时,虽然旧数据可能仍然存在于更早的 SSTable 里,但由于新的删除标记已经存在,因此查询时会认为该数据已经被删除。只有在后续执行 Compaction 时,系统才会将旧数据以及对应的删除标记进行真正的清理。因此 LSM Tree 的删除本质上更接近于逻辑删除,不是立即进行物理删除。