首页 > 数据库 > > LevelDB 浅析
2006 年,Google 发布了一篇论文Bigtable: A Distributed Storage System for Structured Data[1],描述了一个用于管理结构化数据的分布式存储系统 - Bigtable 的数据模型、接口以及实现等内容。随后,市面上出现了以 Apache HBase 为代表的开源分布式实现版本,以及本文要介绍的,由 Google 自家实现(Bigtable 的作者 Jeff Dean[2] 和 Sanjay Ghemawat[3] 共同完成)的单机引擎库LevelDB[4]。
LevelDB 和基于其衍生的 RocksDB 在业界有很广泛的应用。
LevelDB 是一个高效的 key-value 存储引擎库,由 LSM 树实现,具有优秀的随机写和顺序读写性能,大范围随机读性能稍差,适合用于少量随机查询、大量写入的场景,并且对磁盘的利用非常高效。
主要特性如下:
Put(key,value), Get(key), Delete(key)当然也有一些局限:

关键概念
在写入内存之前,为了保证意外掉电、重启等操作不丢数据,会先写 log(即 WAL),写成功之后再写入内存。如果发生意外,可以从 log 中恢复数据。
LevelDB 为了保证写入的高效,所有写入操作会先写内存结构 MemTable,当 MemTable 达到阈值(默认 4M)后,会转变成为只读的 Immutable MemTable,等待压缩线程写入磁盘,此时 LevelDB 会生成新的 MemTable 以供写入。
LevelDB 不仅能写入,还能删除数据,在做删除操作时,不会做物理删除,只是在对应数据上标记删除,等待压缩写盘时忽略掉,这样做是为了减少 MemTable 数据结构维护的代价,以及减少因此带来的并发竞争状态。
为了兼顾 MemTable 的读写速度,以及存储空间使用,采用了 skiplist 结构。skiplist 可以简单理解为一个拥有多级索引的链表,读取的时间复杂度为 O(n),理论上写入时间复杂度为 O(1),但是写入前必须找到对应的节点位置,所以写入复杂度也降级到 O(n)。

Immutable MemTable 本质上和 MemTable 是同一个东西,结构一样。
值得一提的是,redis 里的 hash/zset 在容量较小的时候也是用了 skiplist,目的是减少内存使用。
如前文所述,当 MemTable 达到阈值(默认 4M)后,会转变成为只读的 Immutable MemTable,这时候会顺带触发一个 minor compaction,将 Immutable MemTable 持久化成 sst。
下面着重分析一下 sst

sst 文件内部划分成固定大小的 block,每个 block 包含以下几个部分:

每个 block 可以用来存储不同的内容,有以下几种:

data block 是 LevelDB 承载数据的部分,每一对 kv 都是一个 entry,一个 data block 中有若干个 entry 和少量 restart point 组成。

一个 entry 由几个部分组成:
上图可知,并不是每个 entry 都完整保存了 key 的全部内容,大部分 entry 只存了部分 key,以及和前一个公共 key 部分的长度。
当拥有公共部分 key 的 entry 过多的时候,会影响查找效率,所以每隔几段 entry 会重新完整记录当前 entry 的完整 key,这个完整的 entry 所在位置就被称为 restart point。
具体案例如图所示

这个 block 中保存了这几个 kv:
block 尾部记录了 restart point 信息


index block 相对比较简单,内部有若干 entry,分别记录了对应的每个 data block 的最大 key,offset 和长度,便于读取 sst 时快速 key 定位

filter block 的作用为快速判断一个 key 是否可能在当前 sst 内,为什么说可能呢?filter block 是由布隆过滤器实现,布隆过滤器有以下特性:
如果 filter block 中没发现 key,那么 key 一定不在当前 sst,否则就有可能在,需要进一步去 index block 查找
了解了磁盘结构之后,我们可以来看一下 LevelDB 究竟是怎么把 Immutable MemTable 持久化成 sst 了
Log:最大 4MB (可配置), 会写入 Level 0;
Level 0:最多 4 个 SST 文件;
Level 1:总大小不超过 10MB;
Level 2:总大小不超过 100MB;
Level 3+:总大小不超过上一个 Level ×10 的大小
比如:0 ↠ 4 SST, 1 ↠ 10M, 2 ↠ 100M, 3 ↠ 1G, 4 ↠ 10G, 5 ↠ 100G, 6 ↠ 1T, 7 ↠ 10T
读取操作相比写入要简单一点,过程如下
LevelDB 是单机版的 big table 实现,上层套个 redis 的网络层就可以实现一个兼容 redis 协议的混合存储数据库,如 360 的 SSDB。Facebook 基于 LevelDB 的修改版 RocksDB 被用在了 TiKV 的元数据存储上。理解 LevelDB 对理解其他基于 big table 的分布式存储方案有很大的帮助
Bigtable: A Distributed Storage System for Structured Data: https://static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf
[2]Jeff Dean: https://research.google.com/pubs/jeff.html
[3]Sanjay Ghemawat: https://research.google.com/pubs/SanjayGhemawat.html
[4]LevelDB: https://github.com/google/leveldb
来自:https://mp.weixin.qq.com/s/AtFmCEPLbB4ebrWgfG9hwQ
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/26692020/viewspace-3166909/ ,如需转载,请注明出处,否则将追究法律责任。