LevelDB深入浅出之整体架构

LevelDB是一个可持久化的KV数据库引擎,由Google传奇工程师Jeff Dean和Sanjay Ghemawat开发并开源。无论从设计还是代码上都可以用精致优雅来形容,非常值得细细品味。本文将从整体特性、架构和使用等几方面做一个解释,试图通过本文的介绍让大家对LevelDB有个整体的认识并能够使用。

设计思路

做存储的同学都很清楚,对于普通机械磁盘顺序写的性能要比随机写大很多。比如对于15000转的SAS盘,4K写IO, 顺序写在200MB/s左右,而随机写性能可能只有1MB/s左右。而LevelDB的设计思想正是利用了磁盘的这个特性。
LevelDB的数据是存储在磁盘上的,采用LSM-Tree的结构实现。LSM-Tree将磁盘的随机写转化为顺序写,从而大大提高了写速度。为了做到这一点LSM-Tree的思路是将索引树结构拆成一大一小两颗树,较小的一个常驻内存,较大的一个持久化到磁盘,他们共同维护一个有序的key空间。写入操作会首先操作内存中的树,随着内存中树的不断变大,会触发与磁盘中树的归并操作,而归并操作本身仅有顺序写。如下图所示:

图1 数据存储原理

图中2个红色区域是要进行归并的数据块,计算出顺序后会存储到如图下面的磁盘空间,而这种存储方式是追加式的,也就是顺序写入磁盘。
随着数据的不断写入,磁盘中的树会不断膨胀,为了避免每次参与归并操作的数据量过大,以及优化读操作的考虑,LevelDB将磁盘中的数据又拆分成多层,每一层的数据达到一定容量后会触发向下一层的归并操作,每一层的数据量比其上一层成倍增长。这也就是LevelDB的名称来源。

主要特性

下面是LevelDB官方对其特性的描述,主要包括如下几点:

  1. key和value都是任意长度的字节数组;
  2. entry(即一条K-V记录)默认是按照key的字典顺序存储的,当然开发者也可以重载这个排序函数;
  3. 提供的基本操作接口:Put()、Delete()、Get()、Batch();
  4. 支持批量操作以原子操作进行;
  5. 可以创建数据全景的snapshot(快照),并允许在快照中查找数据;
  6. 可以通过前向(或后向)迭代器遍历数据(迭代器会隐含的创建一个snapshot);
  7. 自动使用Snappy压缩数据;
  8. 可移植性;

编译和使用

LevelDB的编译也是比较简单的,可以从官网直接克隆代码。https://github.com/google/leveldb,具体操作步骤如下(可以参考源代码中的README文件):

git clone https://github.com/google/leveldb.git
cd leveldb
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .

完成上述几步,就可以编译出一个静态库、一个动态库和一些测试程序。我们可以自己写一个测试代码进行测试。比如我们在leveldb目录下面创建一个test目录, 然后将静态库libleveldb.a拷贝进来,然后在其中创建一个名为test.cpp的文件,文件内容如下:

#include <assert.h>
#include <iostream>
#include <sstream>
#include "leveldb/db.h"

using namespace std;

int main(){
    leveldb::DB* db; 
    leveldb::Options options;
    options.create_if_missing = true;
    //打开一个数据库
    leveldb::Status status = leveldb::DB::Open(options,"./testdb1",&db);
    int count = 0;

    //循环多次,不断添加内容
    while (count < 1000) {
        std::stringstream keys ;
        std::string key;
        std::string value = "shuningzhang@itworld123.com";

        keys << "itworld123-" << count;
        key = keys.str();
        status = db->Put(leveldb::WriteOptions(), key, value);//添加内容
        assert(status.ok());

        status = db->Get(leveldb::ReadOptions(), key, &value);//获取
        assert(status.ok());
        std::cout<<value<<std::endl;

        count ++; 
    }   
  
    delete db; //关闭数据库

    return 0;  
}

测试程序功能很简单,就是向KV数据库添加1000个KV数据。后续我们还会用到这个程序,这里了解一下就行。具体通过如下命令可以编译成可执行程序。

g++ -o leveldbTest test.cpp libleveldb.a -lpthread -lsnappy

如果运行一下该程序,可以看到在当前目录会生成一个名为testbd1的目录,其中的内容如下所示:


图2 LevelDB的主要文件

整体结构

对LevelDB有一个整体的认识之后,我们分析一下它的架构。这里面有一个重要的概念(或者模块)需要理解,分别是内存数据的Memtable,分层数据存储的SST文件,版本控制的Manifest、Current文件,以及写Memtable前的WAL。这里简单介绍各个组件的作用和在整个结构中的位置,更详细的介绍本号将另外写文章进行介绍。在介绍之前,我们先看一下整体架构示意图:


图3 LevelDB整体架构图

如图3所示,对于写数据,接口会同时写入内存表(MemTable)和日志中。当内存表达到阈值时,内存表冻结,变为Immutable MemTable,并将数据写入SST表中,其中SST表时在磁盘上的文件。下面是涉及到主要模块的简单介绍:

  • Memtable:内存数据结构,跳表实现,新的数据会首先写入这里;
  • Log文件:写Memtable前会先写Log文件,Log通过append的方式顺序写入。Log的存在使得机器宕机导致的内存数据丢失得以恢复;
  • Immutable Memtable:达到Memtable设置的容量上限后,Memtable会变为Immutable为之后向SST文件的归并做准备,顾名思义,Immutable Mumtable不再接受用户写入,同时会有新的Memtable生成;
  • SST文件:磁盘数据存储文件。分为Level 0到Level N多层,每一层包含多个SST文件;单层SST文件总量随层次增加成倍增长;文件内数据有序;其中Level0的SST文件由Immutable直接Dump产生,其他Level的SST文件由其上一层的文件和本层文件归并产生;SST文件在归并过程中顺序写生成,生成后仅可能在之后的归并中被删除,而不会有任何的修改操作。
  • Manifest文件: Manifest文件中记录SST文件在不同Level的分布,单个SST文件的最大最小key,以及其他一些LevelDB需要的元信息。
  • Current文件: 从上面的介绍可以看出,LevelDB启动时的首要任务就是找到当前的Manifest,而Manifest可能有多个。Current文件简单的记录了当前Manifest的文件名,从而让这个过程变得非常简单。

写流程简析

了解了整体流程和架构后,我们分析两个基本的流程,也就是LevelDB的写流程和读流程。我们这里首先分析一下写流程,毕竟要先有数据后才能读数据。
LevelDB的写操作包括设置key-value和删除key两种。需要指出的是这两种情况在LevelDB的处理上是一致的,删除操作其实是向LevelDB插入一条标识为删除的数据。下面我们先看一下LevelDB插入值的整体流程,具体如图4所示。


图4 LevelDB写数据流程

具体代码请自行阅读,本文不贴过多的代码。这里需要重点说明的是DBImpl::Write函数,如图5是该函数的代码片段,从这段代码中我们可以很清楚的看到数据被分别写入日志和内存2个地方。其它代码都比较简单,大家请自行对照流程图阅读。


图5 DBImpl::Write代码片段

读流程简析

读流程要比写流程简单一些,核心代码逻辑如图6所示。首先,生成内部查询所用的Key,该Key是由用户请求的UserKey拼接上Sequence生成的。其中Sequence可以用户提供或使用当前最新的Sequence,LevelDB可以保证仅查询在这个Sequence之前的写入。然后,用生成的Key,依次尝试从 Memtable,Immtable以及SST文件中读取,直到找到。

图6 LevelDB读流程
  • 从SST文件中查找需要依次尝试在每一层中读取,得益于Manifest中记录的每个文件的key区间,我们可以很方便的知道某个key是否在文件中。Level0的文件由于直接由Immutable Dump 产生,不可避免的会相互重叠,所以需要对每个文件依次查找。对于其他层次,由于归并过程保证了其互相不重叠且有序,二分查找的方式提供了更好的查询效率。
  • 可以看出同一个Key出现在上层的操作会屏蔽下层的。也因此删除Key时只需要在Memtable压入一条标记为删除的条目即可。被其屏蔽的所有条目会在之后的归并过程中清除。

好了,今天就先到这,后续我们在深入的介绍LevelDB的其它部分的,并且逐步深入,理解其内部的精髓。

关注微信公众号,获取信息更及时: itworld123

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • LevelDB是Google传奇工程师Jeff Dean和Sanjay Ghemawat开源的KV存储引擎,无论从...
    CatKang阅读 4,817评论 5 25
  • 【转自】http://alinuxer.sinaapp.com/?p=400 LDB 首先,我们先总结下googl...
    lxqfirst阅读 7,915评论 0 2
  • 版本控制或元信息管理,是LevelDB中比较重要的内容。本文首先介绍其在整个LevelDB中不可替代的作用;之后从...
    CatKang阅读 5,452评论 12 12
  • # LevelDB简单介绍 ------ LevelDB是Google开源的持久化KV单机数据库,具有很高的随机写...
    ClimbYang阅读 517评论 0 0
  • CT Walk of Shame Givenchy 311 312 103 318 Dior 772 080 雅诗...
    SeoMR96阅读 99评论 0 0