首页 > 其他分享 >论文解读:LSM Tree 的魔力,提升写入吞吐量的高效数据存储结构

论文解读:LSM Tree 的魔力,提升写入吞吐量的高效数据存储结构

时间:2024-08-05 09:24:12浏览次数:16  
标签:魔力 写入 self LSM Tree 内存 组件 磁盘

LSM Tree是一种用于高写入吞吐量的数据库存储引擎,广泛应用于现代分布式数据库系统。其核心思想是将写入操作缓存在内存中,并定期批量写入磁盘,减少磁盘 I/O 操作,提高写入性能。因其高效的写入性能和适应大规模数据的能力,成为现代数据密集型应用的关键技术之一。

LSM-tree主要由三部分组成:Memtable、SSTable和WAL(Write-Ahead Log)。数据首先写入内存中的Memtable,当Memtable满了,就会将其转化为只读的SSTable存储在磁盘上。同时,WAL 记录了每次写操作,以确保数据的可靠性。

WAL是一种非常重要的数据库技术,在很多数据库中我们都可以见到其身影,核心思想是将事务操作先记录到磁盘的日志文件中,然后在批量写入物理存储,我一直觉得,LSM-tree中连续批量写入数据到SSTable的思想,本身就跟WAL的思想有很相似的地方。

图片

"The log-structured merge-tree (LSM-tree)" by Patrick O'Neil是LSM Tree的开创性论文,介绍了LSM Tree的基本结构和设计理念。

论文首先将LSM树和数据库中传统使用的B树索引结构进行的对比,LSM树大大减少了磁盘臂的移动,从而提高了数据写入的成本性能,其最大优势在于写入性能。通过批量写入和合并操作,它能够高效地处理大量写请求,适用于写密集型应用场景。

传统的B树就像是将每本书都按顺序放到书架上,这样查找起来很方便,但每次放书都要找到合适的位置,费时费力。而 LSM树则不同,它更像是先把书随手放到一个临时箱子里(Memtable),等箱子满了再一次性分类整理到书架上(SSTable)。

LSM树的核心组建和运作机制

LSM树由两个或多个类似树形的数据结构组成,其中较小的结构(C0)完全驻留在内存中,而较大的结构(C1及其以上)则存储在磁盘上。

当新的历史记录插入时,首先将其索引信息插入到C0树中,然后通过一个称为“滚动合并”的算法将索引信息迁移到C1树。滚动合并过程中,C0树中的部分索引信息被删除并与C1树中的索引信息合并,最终将合并后的数据写入磁盘。

滚动合并算法的步骤如下:首先读取包含 C1 树叶子节点的多页块,然后读取该块中的磁盘页,将其与 C0 树叶子层中的条目合并,并创建一个新的合并后的 C1 树叶子节点。

每次合并步骤都会产生一个空块(包含尚未合并的条目)和一个满块(包含合并后的条目)。满块会被写入磁盘,而空块则保留在内存中,以备后续合并步骤使用,磁盘上所有块都是满的,这是LSM树和B树非常不同的地方。

C1 树的目录节点也存储在内存中,用于高效地访问叶子节点。目录节点会定期刷新到磁盘,以确保数据持久性。

class LSMTree:
    def __init__(self):
        self.memtable = Memtable()
        self.wal = WAL()
        self.sstables = []

    def insert(self, key, value):
        # 写入WAL以确保数据可靠性
        self.wal.append((key, value))
        # 写入 Memtable
        self.memtable.put(key, value)
        # 检查Memtable是否已满
        if self.memtable.is_full():
            # 将Memtable持久化为SSTable
            new_sstable = self.memtable.to_sstable()
            self.sstables.append(new_sstable)
            self.memtable.clear()

LSM树的更多操作

在进行查找时,系统会首先在C0树中查找,如果找不到,则会在 C1 树中查找。

  def get(self, key):
      # 首先在Memtable中查找
      value = self.memtable.get(key)
      if value is not None:
          return value
      # 如果未找到,再依次在SSTable中查找
      for sstable in reversed(self.sstables):
          value = sstable.get(key)
          if value is not None:
              return value
      return None

删除操作通过标记删除状态实现,实际删除会在合并过程中进行:

    def delete(self, key):
        # 在WAL中记录删除操作
        self.wal.append((key, None))
        # 在Memtable中标记删除
        self.memtable.put(key, None)

LSM树的更新操作可以通过先删除再插入来实现。

成本性能和数据模型

文章中提到的 “The Five Minute Rule” 是一种评估内存和磁盘之间数据访问成本效益的规则。它指出,当页面引用频率超过每 60 秒一次时,使用内存缓存页面可以减少磁盘IO,从而降低系统开销。

论文中深入的比较了B树和LSM树的性能差异,本文略过这个部分,更多关注点放在LSM树的工作机制上。

数据温度反映了数据被访问的频率,根据数据温度,可以决定数据最佳的存储方式。将磁盘模型划分为冷数据、温数据和热数据三个区

冷数据是访问频率极低,几年以上才会访问的旧数据,磁盘容量是主要瓶颈,用磁盘存储,可以最大化空间利用率;

温数据的访问频率适中,几天时间访问一次,需要平衡磁盘臂利用率和磁盘空间,用内存缓冲区来缓存频繁使用的数据页,可以减少磁盘IO;

最后是访问频率极高的热数据,每秒几十次访问,内存成本是主要瓶颈,应该放在内存中,最大化访问速度。

我们在日常业务应用开发中,设计缓存和选择数据存储引擎的时候,也应该参考数据温度,针对不同访问频率,决定如何存储和查询特定的数据。

图片

多页块IO

LSM树使用滚动合并的方式将内存中的索引条目迁移到磁盘上的索引中。滚动合并过程中,每次合并多个索引条目到磁盘上的一个页面中,从而实现批量读写。它的磁盘索引结构采用 100% 填充的页面节点,并使用连续的多页块存储,进一步优化磁盘访问效率。

多页块I/O是LSM树的核心优势之一,它通过批量读写、减少磁盘访问成本和提高磁盘访问效率等方式,有效地提升了LSM树的性能。

降低磁盘访问成本的原理,是因为多页块 I/O 可以一次性读写多个页面,从而减少磁盘臂的移动次数,降低寻道时间。一次性读写多个连续页面,减少旋转次数,从而降低旋转延迟。多页块I/O还可以利用磁盘的连续存储空间,减少磁盘碎片

然而,多页块I/O也存在一些局限性,例如内存占用和写放大问题。

多组件LSM树

以上我们谈论的LSM树都是单组件的,当C0组件相对于C1组件变得非常大时,会导致内存成本过高。为了解决这个问题,可以引入多组件LSM树,其中包含C0、C1、C2、…、Ck-1和Ck等多个组件,组件大小依次递增。每个组件都是一个索引树结构,其中C0组件是内存驻留的,而所有其他组件都是磁盘驻留的。

多组件LSM树中,每个组件都有一个大小参数S(Ci);根据一个恒定的插入率R,向C0组件中插入字节;当某个组件的大小超过阈值时,该组件的条目会通过滚动合并迁移到下一个更大的组件,直到所有条目迁移到Ck。

多组件LSM树有几个优势,通过增加组件数量,将C0组件的大小进一步扩大,每个合并步骤中合并到C1组件的条目数量会更多,就提高了批处理效率,减少了磁盘的IO;通过将C0组件的大小最大化,可以减少所需的内存容量,从而降低内存成本;通过合理分配组件大小,确保磁盘IO速率始终保持在较高水平。

▲ LevelDB中LSM-tree的实现

论文中还花很多篇幅,对比了LSM树和B树还有其他存储结构,并且讨论了LSM树的并发恢复机制,本文重点放在工作机制,所以没有展开讨论相关的内容。

总结

LSM-tree在处理大规模、高并发数据写入方面表现优异,为现代数据库管理系统提供了强大的支持,在很多知名的互联网数据库中有着广泛的应用;例如LevelDB、RocksDB、Apache Cassandra。

随着新型硬件的发展,LSM树的研究也在不断推进。例如,结合NVMe SSD等高性能存储介质,可以显著提高 LSM树的读写性能。

深入了解其工作机制,有助于我们更好地理解如何优化存储性能的思想,在业务开发中,也可以运用这些思想,解决存储性能问题。

论文解读:LSM Tree 的魔力,提升写入吞吐量的高效数据存储结构icon-default.png?t=N7T8https://mp.weixin.qq.com/s/7iD6JdrmG8jBi1QC4pbUHQ

标签:魔力,写入,self,LSM,Tree,内存,组件,磁盘
From: https://blog.csdn.net/liuwill/article/details/140917859

相关文章

  • 使用django-treebeard实现树类型存储与编辑
    前言其实之前做很多项目都有遇到跟树相关的功能,以前都是自己实现的,然后前端很多UI组件库都有Tree组件,套上去就可以用。不过既然用Django了,还是得充分发挥一下生态的优势,但是我找了半天,也就这个treebeard能用,其他要不停更了要不就功能很拉,没有可视化编辑树的功能。难道Djang......
  • Luogu P10842 Piggy and Trees 题解 [ 绿 ] [ 拆边 ] [ 贡献思维 ]
    PiggyandTrees:把路径拆成边的思维题。思路一看到这题的路径,就想到了LuoguP3177树上染色这题化路径为边的贡献,分别计算的思维。那么对于此题,先来观察题目里式子的意思:对于树上的每个无序点对,求出树上每个点到这些点对之间的最短路径的距离之和。枚举点对对应的就是前两......
  • 陀螺仪LSM6DSOW开发(7)----融合磁力计进行姿态解算
    陀螺仪LSM6DSOW开发.7--融合磁力计进行姿态解算概述视频教学样品申请源码下载硬件准备DataLogFusion磁力计校准过程初始化磁力计MFX_Arithmetic_Init卡尔曼滤波算法演示概述MotionFX库包含用于校准陀螺仪、加速度计和磁力计传感器的例程。将磁力计的数据与加速度计......
  • 树(tree) - 题解(带权并查集)
    树(tree)时间限制:C/C++2000MS,其他语言4000MS内存限制:C/C++256MB,其他语言512MB描述给定一个\(n\)个结点,\(n−1\)条边的有根树。第\(i\)条边可以用(\(a_i,b_i\))来描述,它表示连接结点\(a_i\)和结点\(b_i\)的一条边,其中结点\(a_i\)是结点\(b_i\)的父节点。......
  • [AGC023F] 01 on Tree
    题意给定一棵\(n\)个节点的树,每个点都有权值\(0/1\),每次删除一个没有父亲的节点,并将权值放在序列末尾。求该序列最小的逆序对数。Sol删除不好做,只能\(\text{dp}\)。考虑把删除改成合并,每次合并\(x\)和\(fa_x\)表示将\(x\)紧接在\(fa_x\)后面。这样维护\(n\)个......
  • SP3912 MTREECOL - Color a tree
    前言NOIP模拟考到了这题,整场比赛死磕这题,最后悲痛拿下\(\text{0+30+0+0=30pts}\)的高分。Solution题意很清楚。每一次染色操作当且仅当父亲节点染过色。每一个节点贡献的价值是点权乘上时间。求贡献和最小。设当前权值最大的节点为\(x\),那么如果\(x\)之前的节点......
  • [学习笔记]最小割树 (Gomory-Hu Tree)
    本文是在作者阅读多篇博客后糅合而成的,部分内容有雷同。最小割树又称Gomory-Hu树,由RalphEdwardGomory和TeChiangHu于1961年发表的论文中共同提出。最小割树可以在\(n−1\)次最大流中构建,并通过树上RMQ求任意两点之间的最小割。板子题:P4897【模板】最小割树(G......
  • Gartner 魔力象限:安全信息和事件管理 (SIEM) 2024
    GartnerMagicQuadrantforSecurityInformationandEventManagement2024Gartner魔力象限:安全信息和事件管理2024请访问原文链接:https://sysin.org/blog/gartner-magic-quadrant-siem-2024/,查看最新版。原创作品,转载请保留出处。Gartner魔力象限:安全信息和事件管理202......
  • Solution - Atcoder AGC052B Tree Edges XOR
    令\(w_{(u,v)}\)为边\((u,v)\)的边权。考虑到对于一条边进行操作影响的是有公共点的边,于是一个想法是把边权转到点权,用点权来表示边权。于是考虑对于每个点构造\(w_u\)使得\(w_{(u,v)}=w_u\oplusw_v\)。因为这是一颗树,所以一定存在合法的构造。其实到了这里,这种......
  • Solution - Atcoder APC001E Antennas on Tree
    首先考虑判定什么样的选取是合法的。考虑到令任意一个点\(u\)为根。若\(u\)有至少两个子树没有点选中,那么这两个子树是无法区分的。所以可以知道需要满足任意一个点为根,都至多存在一个子树内部没有选中的点。接下来就要贪心的选出最少的点了。考虑对于每个点的限制都是子......