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,所以需要合并优化包括丢弃被删除的数据,覆盖旧数据,将新生成的文件推送到更高的层级