LSM树

假如对写操作的吞吐量比较敏感,可采用日志策略(顺序读写,只追加不修改)来提升写性能。存在问题:数据查找需要倒序扫描,花费很多时间。比如,预写日志WAL,WAL的中心概念是数据文件(存储着表和索引)的修改必须在这些动作被日志记录之后才被写入,即在描述这些改变的日志记录被刷到持久存储以后。如果我们遵循这种过程,我们不需要在每个事务提交时刷写数据页面到磁盘,因为我们知道在发生崩溃时可以使用日志来恢复数据库:任何还没有被应用到数据页面的改变可以根据其日志记录重做(这是前滚恢复,也被称为REDO)。使用WAL可以显著降低磁盘的写次数,因为只有日志文件需要被刷出到磁盘以保证事务被提交,而被事务改变的每一个数据文件则不必被刷出

其只是提高了写的性能,对于更为复杂的读性能,需要寻找其他的方法,其中有四种方法来提升读性能:

  1. 二分查找: 将文件数据有序保存,使用二分查找来完成特定key的查找。
  2. 哈希:用哈希将数据分割为不同的bucket
  3. B+树:使用B+树 或者 ISAM 等方法,可以减少外部文件的读取
  4. 外部文件: 将数据保存为日志,并创建一个hash或者查找树映射相应的文件。

所有的四种方法都可以有效的提高了读操作的性能(最少提供了O(log(n)) ),但是,却丢失了日志文件超好的写性能,上面这些方法,都强加了总体的结构信息在数据上,数据被按照特定的方式放置,所以可以很快的找到特定的数据,但是却对写操作不友善,让写操作性能下降。更糟糕的是,当需要更新hash或者B+树的结构时,需要同时更新文件系统中特定的部分,这就是造成了比较慢的随机读写操作,这种随机的操作要尽量减少。

既要保证日志文件好的写性能,又要在一定程度上保证读性能,所以LSM-Tree应运而生。

下面块为引用https://www.cnblogs.com/yanghuahui/p/3483754.html,进行对比

讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来

  • 哈希存储引擎  是哈希表的持久化实现,支持增、删、改以及随机读取操作,但不支持顺序扫描,对应的存储系统为key-value存储系统。对于key-value的插入以及查询,哈希表的复杂度都是O(1),明显比树的操作O(n)快,如果不需要有序的遍历数据,哈希表就是your Mr.Right
  • B树存储引擎是B树(关于B树的由来,数据结构以及应用场景可以看之前一篇博文)的持久化实现,不仅支持单条记录的增、删、读、改操作,还支持顺序扫描(B+树的叶子节点之间的指针),对应的存储系统就是关系数据库(Mysql等)。
  • LSM树(Log-Structured Merge Tree)存储引擎和B树存储引擎一样,同样支持增、删、读、改、顺序扫描操作。而且通过批量存储技术规避磁盘随机写入问题。当然凡事有利有弊,LSM树和B+树相比,LSM树牺牲了部分读性能,用来大幅提高写性能。

LSM树(Log Structured Merge Tree,结构化合并树)的思想非常朴素,就是将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘(由此提升了写性能,是一种基于硬盘的数据结构,与B-tree相比,能显著地减少硬盘磁盘臂的开销。当然凡事有利有弊,LSM树和B+树相比,LSM树牺牲了部分读性能,用来大幅提高写性能。

读取时需要合并磁盘中的历史数据和内存中最近的修改操作,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件(存储在磁盘中的是许多小批量数据,由此降低了部分读性能。但是磁盘中会定期做merge操作,合并成一棵大树,以优化读性能)。LSM树的优势在于有效地规避了磁盘随机写入问题,但读取时可能需要访问较多的磁盘文件。

代表数据库:nessDB、leveldb、hbase等

核心思想的核心就是放弃部分读能力,换取写入的最大化能力,放弃磁盘读性能来换取写的顺序性。极端的说,基于LSM树实现的HBase的写性能比Mysql高了一个数量级,读性能低了一个数量级。

LSM操作

LSM树 插入数据可以看作是一个N阶合并树。数据写操作(包括插入、修改、删除也是写)都在内存中进行,

数据首先会插入内存中的树。当内存树的数据量超过设定阈值后,会进行合并操作。合并操作会从左至右便利内存中树的子节点 与 磁盘中树的子节点并进行合并,会用最新更新的数据覆盖旧的数据(或者记录为不同版本)。当被合并合并数据量达到磁盘的存储页大小时。会将合并后的数据持久化到磁盘,同时更新父节点对子节点的指针。

LSM树 读数据 磁盘中书的非子节点数据也被缓存到内存中。在需要进行读操作时,总是从内存中的排序树开始搜索,如果没有找到,就从磁盘上的排序树顺序查找。

在LSM树上进行一次数据更新不需要磁盘访问,在内存即可完成,速度远快于B+树。当数据访问以写操作为主,而读操作则集中在最近写入的数据上时,使用LSM树可以极大程度地减少磁盘的访问次数,加快访问速度。

LSM树 删除数据 前面讲了。LSM树所有操作都是在内存中进行的,那么删除并不是物理删除。而是一个逻辑删除,会在被删除的数据上打上一个标签,当内存中的数据达到阈值的时候,会与内存中的其他数据一起顺序写入磁盘。 这种操作会占用一定空间,但是LSM-Tree 提供了一些机制回收这些空间。

### LSM数据结构及其实现原理 #### 什么是LSMLSM(Log-Structured Merge Tree)是一种高效处理海量据读写的存储引擎设计模式。其核心目标是通过减少随机写入操作的量,从而显著提升写入性能[^3]。 --- #### LSM的核心组件 1. **内存部分 (MemTable)** 写入请求首先被记录到一个称为 MemTable 的内存数据结构中。通常是一个有序的键值对集合,在内存中按顺序排列以便快速查找和插入。当 MemTable 达到一定大小时,会被冻结并持久化到磁盘上作为 SSTable 文件的一部分[^1]。 2. **磁盘部分 (SSTable)** 当 MemTable 被刷写到磁盘时,它会转换成不可变的文件形式,即 SSTable(Sorted String Table)。这些文件按照键值范围分片存储,并且内部按键排序。每次新的 SSTable 创建后,都会触发后台线程执行合并过程以优化整体查询效率。 3. **WAL 日志 (Write-Ahead Log)** 为了防止系统崩溃导致未保存至 MemTable 或 SSTable 中的据丢失,所有的修改操作还会同步追加到 Write-Ahead Log (预写日志)里。这样即使发生意外宕机也能恢复最近的操作记录。 --- #### 工作流程概述 以下是 LSM 的主要工作阶段: 1. **写入路径** - 用户发起写请求时,新条目直接存放到 MemTable 并同时追加到 WAL。 - 如果 MemTable 填满,则将其内容转储为一个新的 SSTable 文件并刷新到硬盘上。 2. **读取路径** - 对于每一次读取请求,系统依次检查多个位置:首先是当前活跃的 MemTable;其次是尚未完成合并的老版本 SSTables 和最新生成的新版 SSTables。 - 查询过程中可能涉及多层不同时间戳下的副本比较,最终返回最新的有效结果[^2]. 3. **Compaction 合并机制** 随着时间推移,会产生越来越多的小型 SSTable 文件。为了避免过多碎片化的索引影响检索速度,周期性的 Compaction 进程负责将若干个小表合并成为一个更大的全局一致视图。此步骤不仅能够消除重复项或者标记已删除项目,还能重新整理物理布局使得后续访问更加紧凑连续。 --- #### 性能特点分析 - **优势** - 提高了大批量持续写入场景下的吞吐能力,因为大部分实际改动都发生在易失性 RAM 缓冲区内而不是昂贵缓慢的传统机械硬盘介质之上; - 减少了因频繁覆盖造成的额外开销,特别是在 SSD 上表现尤为明显由于减少了擦除次延长使用寿命; - 支持动态调整参比如压缩比率、扇区尺寸等满足特定应用需求. - **劣势** - 可能带来较高的延迟波动尤其是对于单个事务而言如果正好赶上正在进行的大规模 compactions 操作期间; - 相较传统 B+Trees 来说初始构建成本较高并且维护复杂度也有所增加. ```python class LSMTNode: def __init__(self, key=None, value=None): self.key = key self.value = value def write_to_memtable(memtable, key, value): memtable[key] = value def flush_memtable_to_disk(memtable): sstable_file = [] sorted_items = dict(sorted(memtable.items())) for k,v in sorted_items.items(): sstable_file.append((k,v)) return sstable_file mem_table = {} write_to_memtable(mem_table,"key1","value1") # Simulate writing to memory table. flushed_data = flush_memtable_to_disk(mem_table) # Flush data when full or triggered by policy. print(flushed_data) ``` 上述代码片段展示了如何模拟向 MemTable 插入一条记录以及之后如何把整个表格的内容导出成为 SSTable 形式的列表对象。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值