下午听了关于MyRocks-PASV的研究讲座,很有意思所以学习了一下LSM树的一些简单的底层原理。现在整理一下


我们都知道目前Key:Value型的数据库普遍较之关系型数据库有着更好的表现,为什么会有这样的一个差异呢?关键就在于存储形式和读写机制的不同。Key:Value型数据库可以通过LSM Tree(Log-Structured-Merge-Tree)来进行存储,而以MySQL为代表的关系型数据库则以B+树的形式来组织聚簇索引文件和二级索引文件来进行存储。二者的实现机制由于是否顺序写产生了很大的差别。

LSM树的具体机制

LSM树其实并不是一个真正意义上的树形结构,其核心特点是利用顺序写来提高写性能,顺序写很好理解。举个很多人都背过的例子就是MySQL的InnoDB引擎在写入内容时会首先通过WAL机制,先将改动写进磁盘中的redo log这个物理日志中,物理日志记录的是对某表的某数据页某偏移量处做了某更新,然后再找机会把redo log中的内容刷进磁盘中真正存储数据的地方。这么做的好处就是因为写入物理日志只需要接着之前写到的位置往下写就行,不需要随机存取磁盘内容,可以进行的相对快速。

但问题就是,MySQL终究还是要把redo log中的操作写入磁盘中真正存储数据的地方,而这个动作就限制了关系型数据库的性能发挥。而LSM树就是直接将WAL机制作为存储数据的主要机制来实现数据库的存取。

如图所示,LSM树有以下三个重要组成部分

  • MemTable
  • Immutable MemTable
  • SS Table

MemTable

MemTable是在内存中的数据结构,用于保存最近更新的数据操作,这里会按照Key有序地组织这些数据。至于具体如何组织这些数据以使其按照Key有序,LSM树并没有做出相应的规定,可以自行实现。

要注意的是因为数据暂时保存在内存中,那么如果断电了就会存在丢失数据的风险,因此这里还是会跟InnoDB一样通过WAL机制来写入磁盘,以保证数据不会因为崩溃或断电而丢失。

Immutable MemTable

当MemTable存储的数据达到阈值后,就会将该Memtable就地转化成Immutable MemTable。Immutable MemTable是将转MemTable变为SSTable的一种中间状态。你可以理解其为一个暂存文件,该文件不再继续写入,而是等待刷入磁盘的SSTable中。之后的写入工作则由一个新创建的MemTable处理。

SSTable(Sorted String Table)

其本质是有序键值对的集合文件,是LSM树在磁盘中的数据结构,我们可以建立key的索引来加快查找。

重点来了,LSM树会将所有的数据插入、修改、删除等操作记录(注意是操作记录)保存在内存之中,当此类操作达到一定的数据量后,再批量地顺序写入到磁盘当中。注意,这与B+树不同,B+树数据的更新会直接在原数据所在处修改对应的值,但是LSM数的数据更新是日志式的,就跟上面说的WAL机制的redo log一样,一条数据更新是直接将更新记录写进log的最后来完成的。而这样设计的目的就是为了顺序写,我们只需要不断地将Immutable MemTable刷入磁盘进行持久化存储即可,不用去修改之前的SSTable中的key,也就保证了顺序写,提升了效率。

不过不断地向后写也就意味着,在不同的SSTable中,可能存在相同Key的记录,显然最新的那条记录才是真实的。那么这样设计的虽然大大提高了写性能,但同时也会带来一些问题:

  • 冗余存储,对于某个key,除了最新的那条记录外,其他的记录都是冗余无用的,但是仍然占用了存储空间。这里LSM树引入了Compact操作(合并多个SSTable)来清除冗余的记录。
  • 读取时需要从最新的记录反向进行查询,直到找到某个key的记录。最坏情况需要查询完所有的SSTable,这里可以通过索引/布隆过滤器来优化查找速度。

Compact策略

讲到SSTable,我们可以看到这里从MemTable到SSTable一路下来全是顺序写的,问题是磁盘容量并不是无限的,何况SSTable中实际上的真实数据只有最新的那一条,所以如何对SSTable进行Compact来释放空间是很重要的。

Compact释放空间的策略讲到底就是围绕着三大性能的权衡策略。即在以下三个问题中,我们必须至少接受其中之一:

  • 读放大:读取数据时实际读取的数据量大于真正的数据量。

    • 例如在LSM树中需要先在MemTable查看当前key是否存在,不存在继续从SSTable中寻找。
  • 写放大:写入数据时实际写入的数据量大于真正的数据量。
    • 例如在LSM树中写入时可能触发Compact操作,导致实际写入的数据量远大于该key的数据量。
  • 空间放大:数据实际占用的磁盘空间比数据的真正大小更多。
    • 上面提到的冗余存储,对于一个key来说,只有最新的那条记录是有效的,而之前的记录都是可以被清理回收的。

size-tiered 策略

简单来说就是把SSTable分层,限制各层的SSTable数量,并且要求每一层的SSTable的大小都要相近,注意不是相同。当上层SSTable过多时,就将多出来的SSTable合并,作为一个更大的SSTable存入下一层。

可以看出,当层数达到一定数量时,最底层的单个SSTable的大小会变得非常大。而且这种策略会导致空间放大严重。因为即使对于同一层的SSTable,每个key的记录是可能存在多份的,只有当该层的SSTable执行compact操作才会消除这些key的冗余记录,那么积累到整个结构中,冗余的记录占比可想而知。

leveled 策略

leveled策略也是采用分层的思想,与size-tiered策略不同的地方在于,leveled策略会将每一层切分成多个大小相近的SSTable,并且保证这些SSTable是这一层是全局有序的,而这就意味着一个key在每一层至多只有1条记录,不存在冗余记录。

Leveled策略是通过合并策略来保证每一层的SSTable全局有序的。具体实现方法为当某一层总大小超过限制,那么选择该层中与下一层存在交集的SSTable文件进行合并并放入下一层,重复这个操作直到该层大小恢复到限制以内为止。并且,多个不相干的合并是可以并发进行的,这大大提高了效率。

这种策略极大缓解了空间放大的问题,但是代价是写放大问题更加突出。在最坏的情况下,如果该层某个SSTable的key的范围跨度非常大,覆盖了下一层所有key的范围,那么进行Compact时将涉及下一层的全部数据。

不过这里只是简单的聊了一下这些机制,具体使用LSM树进行存储的那些应用中,基本都对它们进行了进一步的优化。这里不再细说

基于LSM树的存储机制简述的更多相关文章

  1. HBase LSM树存储引擎详解

    1.前提 讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎. B树存储引擎. LSM树(Log-Structured Merge Tree)存储引擎. 2. 哈希 ...

  2. 面对key数量多和区间查询低效问题:Hash索引趴窝,LSM树申请出场

    摘要:Hash索引有两个明显的限制:(1)当key的数量很多时,维护Hash索引会给内存带来很大的压力:(2)区间查询很低效.如何对这两个限制进行优化呢?这就轮到本文介绍的主角,LSM树,出场了. 我 ...

  3. LSM树由来、设计思想以及应用到HBase的索引

    讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎  是哈希表的持久化实现,支持增.删.改以及随机读取操作,但不支持顺序扫描,对应的存储系统为key-value存储 ...

  4. LSM树由来、设计思想以及应用到HBase的索引(转)

    转自: http://www.cnblogs.com/yanghuahui/p/3483754.html 讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎  是哈 ...

  5. 为什么选择b+树作为存储引擎索引结构

    为什么选择b+树作为存储引擎索引结构 在数据库或者存储的世界里,存储引擎的角色一直处于核心位置.往简单了说,存储引擎主要负责数据如何读写.往复杂了说,怎么快速.高效的完成数据的读写,一直是存储引擎要解 ...

  6. LSM树以及在hbase中的应用

    转自:http://www.cnblogs.com/yanghuahui/p/3483754.html 讲LSM树之前,需要提下三种基本的存储引擎,这样才能清楚LSM树的由来: 哈希存储引擎  是哈希 ...

  7. 17-看图理解数据结构与算法系列(NoSQL存储-LSM树)

    关于LSM树 LSM树,即日志结构合并树(Log-Structured Merge-Tree).其实它并不属于一个具体的数据结构,它更多是一种数据结构的设计思想.大多NoSQL数据库核心思想都是基于L ...

  8. 看图轻松理解数据结构与算法系列(NoSQL存储-LSM树) - 全文

    <看图轻松理解数据结构和算法>,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握.本系列包括各种堆.各种队列.各种列表.各种树.各种图.各种排序等等几十篇的样子. 关于LSM树 ...

  9. MongoDB索引存储BTree与LSM树(转载)

    1.为什么 MongoDB 使用B-树,而不是B+树 MongoDB 是一种 nosql,也存储在磁盘上,被设计用在数据模型简单,性能要求高的场合.性能要求高,我们看B-树与B+树的区别: B+树内节 ...

  10. 【转帖】LSM树 和 TSM存储引擎 简介

    LSM树 和 TSM存储引擎 简介 2019-03-08 11:45:23 长烟慢慢 阅读数 461  收藏 更多 分类专栏: 时序数据库   版权声明:本文为博主原创文章,遵循CC 4.0 BY-S ...

随机推荐

  1. day38-IO流05

    JavaIO流05 4.常用的类04 4.4节点流和处理流03 4.4.8打印流-PrintStream和PrintWriter 打印流只有输出流,没有输入流 1.简单介绍及应用 PrintStrea ...

  2. 解决swiper组件autoplay报错问题

    最近在自定义一个swiper 插件 发现引用之后不定时一直在报错 Uncaught TypeError: Cannot read properties of undefined (reading 'a ...

  3. 微信小程序-前后端交互

    前台手机验证码登录 <view>手机号:</view> <input value="{{phone}}" bindinput="bindPh ...

  4. 第六章:Django 综合篇 - 18:国际化和本地化

    所谓的国际化,是指使用不同语言的用户在访问同一个网站页面时能够看到符合其自身语言的文本页面. 国际化的基本原理是: 浏览器通过LANGUAGE_CODE在HTTP请求头中告诉网站后台服务器用户所需要的 ...

  5. parted创建磁盘分区并创建LVM(Linux合并多块大于2T的磁盘并合并到一个分区)

    文章转载自:https://blog.csdn.net/likemebee/article/details/85630808

  6. Python 类型提示简介

    Python 3.6+ 版本加入了对"类型提示"的支持. 这些"类型提示"是一种新的语法(在 Python 3.6 版本加入)用来声明一个变量的类型. 通过声明 ...

  7. 基于Alpine镜像定制自己的工具箱

    Alpine介绍 Alpine 操作系统是一个面向安全的轻型 Linux 发行版.目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境.这样会带来多个好处. ...

  8. linux主机时间同步

    yum -y install ntpdate ntp && ntpdate cn.pool.ntp.org systemctl start ntpd.service && ...

  9. Fluentd采集示例

    Fluentd通过读取配置文件来加载各插件,日志经由各插件的处理完成输入到输出的整个路由. 本文通过一个最简单的示例来说明配置文件的结构.td-agent.conf默认位于/etc/td-agent/ ...

  10. MySQL数据库-数据表(下)

    分析:给 reader 表添加数据. INSERT INTO:插入数据,插入数据的时候会检查主键或者唯一索引,如果出现重复就会报错: 语法:INSERT INTO table_name VALUES ...