LSM基础概念

LSM Tree

InfluxDB (1.x) 底层存储结构是TSM (Time-Structured Merge Tree ), 实现思想来自于LSM(Log-Structured Merge-Tree),学习 InfluxDB 可以先前置了解 LSM

工作流程

1. 内存中的 MemTable

当有数据写入(比如新增、修改)时,LSM 不会直接写到磁盘,而是先写到内存里的一个结构,叫做 MemTable(内存表)。MemTable 通常用高效的数据结构实现,比如跳表(Skip List)或者红黑树,这样插入和查询都很快速。

2. 日志文件(WAL)

为了防止宕机丢数据,每次写到 MemTable 之前,LSM 都会先把操作记录到一个磁盘上的日志文件,叫 WAL(Write-Ahead Log,预写日志)。这个日志是顺序写入的,所以非常快。 只用于恢复和同步

3. Immutable MemTable 和 SSTable

当 MemTable 满了,它会变成只读的 Immutable MemTable(不可变内存表),然后后台线程会把它刷到磁盘上,变成 SSTable(Sorted String Table,排序字符串表)。SSTable 是磁盘上的文件,数据按键(Key)排序好,并且不可修改。 这就像你把小纸条上的内容整理好,抄到笔记本的某个章节,再也不改动这部分。

4. 多层结构(Level)

磁盘上的 SSTable 会越来越多。为了管理这些文件,LSM 把它们分成多层(Level 0, Level 1, Level 2…)。每一层的数据量通常比上一层大(比如 10 倍),而且数据是有序的。 当某一层的 SSTable 太多时,LSM 会把它们合并(Merge),去掉重复或过时的数据,生成新的 SSTable,放到下一层。这个过程叫 Compaction(合并压缩)

LSM-tree对比Mysql

索引结构更新可以选择两种策略

  • 就地更新: 在原数据页(page/block)上直接修改已有的数据内容 ;Mysql的 B+树

  • 每次修改只操作小部分页,成本较低
  • 插入删除,造成的页分裂只影响部分页,只需局部更新
  • 持久化是随机写,适合读多写少的场景

  • 延迟批量更新: 即更新时先复制一份新页面缓存,再修改,然后用新页面替换旧页面; LSM-Tree ( 先顺序写入 WAL 和 MemTable,最后再合并到 SSTable(类似 COW )

  • 插入还是删除,都会以一个新的记录追加到日志文件
  • 多个小的有序文件会合并,磁盘占用小
  • 顺序写入,适合写多的场景

因此对于大量写入的数据库例如InfluxDB选择“延迟批量更新”性能更好。

持久化

Mysql需要先写入redo log,而LSM不需要先把记录写入日志,是直接内存写入SSTable

Mysql:持久化是记录随机IO,引入了一层redolog日志,提交事务之后是把顺序写入日志,把随机IO转化为顺序IO,用户会感知到写入很快,实际的随机IO是后台执行的

LSM:所有写入首先被顺序追加到MemTable,里面是有序的key,MemTable就是类似于“内存Redo Log”,将其刷新到磁盘SSTable就是一个纯粹的追加写入,不再需要Redo Log来承担这个转换角色; 这样写虽然很快,但是同一个key可能分散在多个sstable,所以需要合并优化包括丢弃被删除的数据覆盖旧数据将新生成的文件推送到更高的层级

合并策略