本文为《数据库系统内幕》第7章的笔记与心得
因为看到OceanBase底层也使用LSM树的实现作为存储引擎,因此特地记下笔记
详见OceanBase文档:https://www.oceanbase.com/docs/community-observer-cn-10000000000901106
简介
LSM树:Log-Structured Merge Tree 日志结构合并树
LSM树是一种典型的不可变结构,不可变存储结构不允许修改现有文件,表只被允许写入一次,新的记录会被附加到新的文件中。他的所有引用都可以被并发地访问,其完整性由不可修改这一事实保证。
相反的概念为原地更新存储结构,如B树:在磁盘上定位到数据后便可读取或写入,但这是以写入性能为代价的,写入会涉及到结构上的递归改变。
不可变LSM树使用仅追加存储和合并协调,而B树则在磁盘上定位数据记录并在文件的偏移量上更新页。
原地更新存储结构针对读取进行了性能优化,但这是以牺牲写入性能为代价的,即 简单读 复杂写;仅追加存储是对写入性能进行的优化,写操作不必在磁盘上找到记录并覆盖,但这是以读性能为代价,读取必须检索多个数据记录的版本,最后合并起来,即 简单写复杂读。
Q:为什么要用不可变结构?(可变B树的缺陷是什么?)
A:由于可变B树采用的结构和构建方法,读写和维护期间的大多数I/O操作都是随机的。每个写操作首先需要定位到具体的页,然后才能修改它。B树要求对已写入的记录进行节点的分裂与合并。一段时间后便需要rebalance,另一个问题是,即使修改了页中的一个单元格,也必须重写整个页。
A:而使用缓冲可以改善空间开销和写放大,通常有两种方式应用缓冲:推迟对磁盘的写入以及使写操作顺序化。
A:保持数据文件的不变性有利于顺序写入:数据被一次性写入磁盘,文件是仅追加的。可变结构也可以一次性预分配数据块,但是后续访问仍需要随机读写。而不可变结构允许我们按照顺序放置数据以防止产生碎片。
A:此外,不可变文件具有更高的数据密度:我们无需为之后将要写入的数据预留任何额外空间(B树预留空间可以为结构变更留下缓冲),也不会因为更新后的记录可能比最初写入的记录需要更多的空间而保留额外空间。
Q:继续说
A:由于文件不可变,所以增删改操作不需要在磁盘上定位数据记录,这显著提高了写入的性能和吞吐量。
A:可变结构采用层级锁和闩锁来确保数据结构的完整性并允许并发读取,但要求写入者对子树具有独占所有权。基于LSM树的存储引擎使用数据和索引文件的线性化内存视图,并且只需要对管理他们的结构进行并发访问保护。
A:当然了,B树和LSM树都需要一些处理来优化性能。LSM树由于分配文件的数量稳定增长,请求的数据可能分布在多个文件中,所以LSM树必须合并和重写文件(类似于redis的AOF)以确保在读取过程中访问尽可能少的文件。另一方面,B树可变文件可能必须被部分或者全部重写,以减少碎片并回收被更新或删除记录所占用的空间(类似于JVM的标记整理法)
什么是LSM树
LSM树 即日志结构合并树的名称取自日志结构文件系统,这种文件系统将磁盘上的所有修改写入一个类似于日志的文件。
LSM树使用缓冲和仅追加存储来实现顺序写操作。它是类似于B树的磁盘驻留结构变体,但节点没有预留空隙,完全被填满,并为顺序磁盘访问进行了优化。
LSM书写入不可变的文件,并随着时间推移合并起来,且通常包含索引,以让读取效率上升。B树通常被用作LSM树的不可变文件的内部索引。
LSM树由内存驻留表MemTable和磁盘驻留表SSTable组成。
LSM树将数据文件写入推迟,并将更改缓存到内存驻留表MemTable中。表的内容会在之后写入不可变磁盘文件。在文件完全持久化之前,可以在内存中访问记录