这是我参与「第四届青训营 」笔记创作活动的的第11天
LSMT工作
Append-only Write + 择机Compact维护索引树结构
数据先写入 MemTable,MemTable 是内存中的索引可以用 SkipList / B+Tree 等数据结构实现。当 MemTable 写到一定阈值后,冻结,成为 ImmemTable,任何修改只会作用于 MemTable,所以 ImmemTable 可以被转交给 Flush 线程进行写盘操作而不用担心并发问题。Flush 线程收到 ImmemTable ,在真正执行写盘前,会进一步从 ImmemTable 生成 SST(Sorted String Table),其实也就是存储在硬盘上的索引,逻辑上和 ImmemTable 无异。
新生成的 SST 会存放于 L0(Layer 0),除了 L0 以外根据配置可以一直有 Ln。SST 每 Compact 一次,就会将 Compact 产物放入下一层。Compact 可以大致理解为 Merge Sort,就是将多个 SST 去掉无效和重复的条目并合并生成新的 SST 的过程。
存储引擎
- 屏蔽 IO 细节提供更好的抽象
- IO 是一种具体实现很复杂,但是逻辑边界很清晰的任务,存储引擎需要屏蔽不同 IO 硬件设备(HDD,SSD,PMem etc),不同系统 API(pread / libaio / iouring)的差别,给出统一的抽象。
- 对于不同硬件设备,存储引擎要能选择最合适的数据分块尺寸,例如 SSD 中一般 Page 大小为 4KB,但在 PMem 中,读写单位就是 256Bytes 了。
- 对于不同的系统,最佳的读写 API 也不同。
- 提供统计信息与 Predicate Push Down 能力
LSMT存储引擎的实现,以 RocksDB 为例
- Write
- RocksDB 在真正执行修改之前会先将变更写入 WAL(Write Ahead Log),WAL 写成功则写入成功。
- 写完 WAL 实际还要写 MemTable,这步相比于写 WAL 到 Page Cache 更耗时而且是可以完全并行化的。RocksDB 在 LevelDB 的基础上主要又添加了并发 MemTable 写入的优化,由最后一个完成 MemTable 写入的 Writer 执行收尾工作。
- RocksDB 在真正执行修改之前会先将变更写入 WAL(Write Ahead Log),WAL 写成功则写入成功。
-
Get && BloomFilter
- 当要进行查找时,对磁盘中的每个SSTable都构建一个布隆过滤器,可以快速判断。然后再SST中可以进行二分查找
-
Compact
- Compact 在 LSMT 中是将 Key 区间有重叠或无效数据较多的 SST 进行合并,以此来加速读取或者回收空间。Compact 策略可以分为两大类。
- Level
- 由于在 LSMT 中,每下一层都会比上一层大 T 倍(可配置),那么假设用户的输入是均匀分布的,每次上下层的合并都一定是一个小 SST 和一个大 SST 进行 Compact。
- Tier 策略允许 LSMT 每层有多个区间重合的 SST,当本层区间重合的 SST 到达上限或者本层大小到达阈值时,一次性选择多个 SST 合并推向下层。Tier 策略理论上 Compact 效率更高,因为参与 Compact 的 SST 大小预期都差不多大,更接近于完美的 Merge Sort。