经典开源代码分析——Leveldb高效存储实现

本文详细分析了Google开源的KV数据库Leveldb的存储结构,包括Log文件、内存中的memtable、磁盘上的sstable,以及sstable的Block结构和Footer。重点探讨了数据的写入、读取和合并流程,展示了如何利用迭代器实现高效的数据访问。通过这些深入理解,揭示了Leveldb高性能背后的关键设计原理。
摘要由CSDN通过智能技术生成

导读:LevelDB是Google开源的持久化KV数据库,在其高性能的背后,将数据拆分成多层进行存储。本文作者深入分析了LevelDB存储模块的设计和源码实现,快速了解LevelDB高性能背后的原理。

作者 codedump codedump.info 博主,多年从事互联网服务器后台开发工作。可访问作者博客阅读 codedump 更多文章。


本文基于leveldb 1.9.0代码。

整体架构

640?wx_fmt=png


如上图,leveldb的数据存储在内存以及磁盘上,其中:

  • memtable:存储在内存中的数据,使用skiplist实现。

  • immutable memtable:与memtable一样,只不过这个memtable不能再进行修改,会将其中的数据落盘到level 0的sstable中。

  • 多层sstable:leveldb使用多个层次来存储sstable文件,这些文件分布在磁盘上,这些文件都是根据键值有序排列的,其中0级的sstable的键值可能会重叠,而level 1及以上的sstable文件不会重叠。


在上面这个存储层次中,越靠上的数据越新,即同一个键值如果同时存在于memtable和immutable memtable中,则以memtable中的为准。


另外,图中还使用箭头来表示了合并数据的走向,即:


640?wx_fmt=jpeg


以下将针对这几部分展开讨论。

Log文件

写入数据的时候,最开始会写入到log文件中,由于是顺序写入文件,所以写入速度很快,可以马上返回。


来看Log文件的结构:

  • 一个Log文件由多个Block组成,每个Block大小为32KB。

  • 一个Block内部又有多个Record组成,Record分为四种类型:

    • Full:一个Record占满了整个Block存储空间。

    • First:一个Block的第一个Record。

    • Last:一个Block的最后一个Record。

    • Middle:其余的都是Middle类型的Record。

  • Record的结构如下:

    • 32位长度的CRC Checksum:存储这个Record的数据校验值,用于检测Record合法性。

    • 16位长度的Length:存储数据部分长度。

    • 8位长度的Type:存储Record类型,就是上面说的四种类型。

    • Header部分

    • 数据部分

640?wx_fmt=png

memtable

memtable用于存储在内存中还未落盘到sstable中的数据,这部分使用跳表(skiplist)做为底层的数据结构,这里先简单描述一下跳表的工作原理。


如果数据存放在一个普通的有序链表中,那么查找数据的时间复杂度就是O(n)。跳表的设计思想在于:链表中的每个元素,都有多个层次,查找某一个元素时,遍历该链表的时候,根据层次来跳过(skip)中间某些明显不满足需求的元素,以达到加快查找速度的目的,如下图所示:


640?wx_fmt=png


在以上这个跳表中,查找元素6的流程,大体如下:

  • 构建一个每个链表元素最多有5个元素的跳表。

  • 由于6大于链表的第一个元素1,因此如果存在必然在1之后的元素中,因此进入元素1的指针数组中,从上往下查找元素4:

    • 第一层:指向的指针为Nil空指针,不满足需求,继续往下查找;

    • 第二层:指向的指针保存的数据为4,小于待查找的元素4,因此如果元素6存在也必然在4之后,因此指针跳转到元素4所在的位置,继续从上往下开始查找。

  • 到了元素4所在的指针数组,开始从上往下继续查找:

    • 第一层:指向的指针保存的数据为6,查找完毕。


从上面的分析过程中可以看到:

  • 跳表是一种以牺牲更多的存储空间换取查找速度,即“空间换时间”的数据结构。

  • 跳表的每一层也都是一个有序链表。

  • 如果一个元素出现在第i层的链表中,那么也必然会在第i层以下的链表中出现。

  • 链表的每个节点中,垂直方向的数组存储的数据都是一样的,水平方向的指针指向链表的下一个元素。

  • 最底层的链表包含所有元素,也就是说,在最底层数据结构退化为一个普通的有序链表。 

sstable文件

大体结构

首先来看sstable文件的整体结构,如下图:


640?wx_fmt=png


sstable文件中分为以下几个组成部分:

  • data block:存储数据的block,由于一个block大小固定,因此每个sstable文件中有多个data block。

  • filter block以及metaindex block:这两个block不一定存在于sstable,取决于Options中的filter_policy参数值,后面就不对这两部分进行讲解。

  • index block:存储的是索引数据,即可以根据index block中的数据快速定位到数据处于哪个data block的哪个位置。

  • footer:脚注数据,每个footer数据信息大小固定,存储一个sstable文件的元信息(meta data)。


可以看到,上面这几部分数据,从文件的组织来看自上而下,先有了数据再有索引数据,最后才是文件自身的元信息。原因在于:索引数据是针对数据的索引信息,在数据没有写完毕之前,索引信息还会发生改变,所以索引数据要等数据写完;而元信息就是针对索引数据的索引,同样要依赖于索引信息写完毕才可以。


block

上面几部分数据中,除去footer之

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值