LevelDB深入淺出之整體架構(gòu)

LevelDB是一個(gè)可持久化的KV數(shù)據(jù)庫(kù)引擎着降,由Google傳奇工程師Jeff Dean和Sanjay Ghemawat開發(fā)并開源鹊碍。無(wú)論從設(shè)計(jì)還是代碼上都可以用精致優(yōu)雅來(lái)形容,非常值得細(xì)細(xì)品味侈咕。本文將從整體特性器紧、架構(gòu)和使用等幾方面做一個(gè)解釋,試圖通過(guò)本文的介紹讓大家對(duì)LevelDB有個(gè)整體的認(rèn)識(shí)并能夠使用熊尉。

設(shè)計(jì)思路

做存儲(chǔ)的同學(xué)都很清楚,對(duì)于普通機(jī)械磁盤順序?qū)懙男阅芤入S機(jī)寫大很多掌腰。比如對(duì)于15000轉(zhuǎn)的SAS盤,4K寫IO齿梁, 順序?qū)懺?00MB/s左右,而隨機(jī)寫性能可能只有1MB/s左右勺择。而LevelDB的設(shè)計(jì)思想正是利用了磁盤的這個(gè)特性。
LevelDB的數(shù)據(jù)是存儲(chǔ)在磁盤上的稿辙,采用LSM-Tree的結(jié)構(gòu)實(shí)現(xiàn)。LSM-Tree將磁盤的隨機(jī)寫轉(zhuǎn)化為順序?qū)懥诖ⅲ瑥亩蟠筇岣吡藢懰俣染稍搿榱俗龅竭@一點(diǎn)LSM-Tree的思路是將索引樹結(jié)構(gòu)拆成一大一小兩顆樹,較小的一個(gè)常駐內(nèi)存萌壳,較大的一個(gè)持久化到磁盤,他們共同維護(hù)一個(gè)有序的key空間袱瓮。寫入操作會(huì)首先操作內(nèi)存中的樹,隨著內(nèi)存中樹的不斷變大绊起,會(huì)觸發(fā)與磁盤中樹的歸并操作燎斩,而歸并操作本身僅有順序?qū)憽H缦聢D所示:

圖1 數(shù)據(jù)存儲(chǔ)原理

圖中2個(gè)紅色區(qū)域是要進(jìn)行歸并的數(shù)據(jù)塊笋鄙,計(jì)算出順序后會(huì)存儲(chǔ)到如圖下面的磁盤空間怪瓶,而這種存儲(chǔ)方式是追加式的,也就是順序?qū)懭氪疟P洗贰。
隨著數(shù)據(jù)的不斷寫入,磁盤中的樹會(huì)不斷膨脹许布,為了避免每次參與歸并操作的數(shù)據(jù)量過(guò)大绎晃,以及優(yōu)化讀操作的考慮蜜唾,LevelDB將磁盤中的數(shù)據(jù)又拆分成多層灵妨,每一層的數(shù)據(jù)達(dá)到一定容量后會(huì)觸發(fā)向下一層的歸并操作落竹,每一層的數(shù)據(jù)量比其上一層成倍增長(zhǎng)货抄。這也就是LevelDB的名稱來(lái)源。

主要特性

下面是LevelDB官方對(duì)其特性的描述积暖,主要包括如下幾點(diǎn):

  1. key和value都是任意長(zhǎng)度的字節(jié)數(shù)組怪与;
  2. entry(即一條K-V記錄)默認(rèn)是按照key的字典順序存儲(chǔ)的,當(dāng)然開發(fā)者也可以重載這個(gè)排序函數(shù);
  3. 提供的基本操作接口:Put()存淫、Delete()、Get()桅咆、Batch()坞笙;
  4. 支持批量操作以原子操作進(jìn)行;
  5. 可以創(chuàng)建數(shù)據(jù)全景的snapshot(快照)籍茧,并允許在快照中查找數(shù)據(jù)梯澜;
  6. 可以通過(guò)前向(或后向)迭代器遍歷數(shù)據(jù)(迭代器會(huì)隱含的創(chuàng)建一個(gè)snapshot);
  7. 自動(dòng)使用Snappy壓縮數(shù)據(jù)腊徙;
  8. 可移植性;

編譯和使用

LevelDB的編譯也是比較簡(jiǎn)單的螟蝙,可以從官網(wǎng)直接克隆代碼民傻。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 .

完成上述幾步牵署,就可以編譯出一個(gè)靜態(tài)庫(kù)喧半、一個(gè)動(dòng)態(tài)庫(kù)和一些測(cè)試程序。我們可以自己寫一個(gè)測(cè)試代碼進(jìn)行測(cè)試取具。比如我們?cè)趌eveldb目錄下面創(chuàng)建一個(gè)test目錄扁耐, 然后將靜態(tài)庫(kù)libleveldb.a拷貝進(jìn)來(lái),然后在其中創(chuàng)建一個(gè)名為test.cpp的文件婉称,文件內(nèi)容如下:

#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;
    //打開一個(gè)數(shù)據(jù)庫(kù)
    leveldb::Status status = leveldb::DB::Open(options,"./testdb1",&db);
    int count = 0;

    //循環(huán)多次,不斷添加內(nèi)容
    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);//添加內(nèi)容
        assert(status.ok());

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

        count ++; 
    }   
  
    delete db; //關(guān)閉數(shù)據(jù)庫(kù)

    return 0;  
}

測(cè)試程序功能很簡(jiǎn)單悔据,就是向KV數(shù)據(jù)庫(kù)添加1000個(gè)KV數(shù)據(jù)。后續(xù)我們還會(huì)用到這個(gè)程序铐姚,這里了解一下就行肛捍。具體通過(guò)如下命令可以編譯成可執(zhí)行程序。

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

如果運(yùn)行一下該程序拙毫,可以看到在當(dāng)前目錄會(huì)生成一個(gè)名為testbd1的目錄,其中的內(nèi)容如下所示:


圖2 LevelDB的主要文件

整體結(jié)構(gòu)

對(duì)LevelDB有一個(gè)整體的認(rèn)識(shí)之后峭跳,我們分析一下它的架構(gòu)缺前。這里面有一個(gè)重要的概念(或者模塊)需要理解,分別是內(nèi)存數(shù)據(jù)的Memtable拯刁,分層數(shù)據(jù)存儲(chǔ)的SST文件逝段,版本控制的Manifest、Current文件奶躯,以及寫Memtable前的WAL。這里簡(jiǎn)單介紹各個(gè)組件的作用和在整個(gè)結(jié)構(gòu)中的位置账嚎,更詳細(xì)的介紹本號(hào)將另外寫文章進(jìn)行介紹儡蔓。在介紹之前,我們先看一下整體架構(gòu)示意圖:


圖3 LevelDB整體架構(gòu)圖

如圖3所示,對(duì)于寫數(shù)據(jù)檩小,接口會(huì)同時(shí)寫入內(nèi)存表(MemTable)和日志中。當(dāng)內(nèi)存表達(dá)到閾值時(shí),內(nèi)存表凍結(jié)卵惦,變?yōu)镮mmutable MemTable瓦戚,并將數(shù)據(jù)寫入SST表中,其中SST表時(shí)在磁盤上的文件较解。下面是涉及到主要模塊的簡(jiǎn)單介紹:

  • Memtable:內(nèi)存數(shù)據(jù)結(jié)構(gòu),跳表實(shí)現(xiàn)啡捶,新的數(shù)據(jù)會(huì)首先寫入這里;
  • Log文件:寫Memtable前會(huì)先寫Log文件奸焙,Log通過(guò)append的方式順序?qū)懭搿og的存在使得機(jī)器宕機(jī)導(dǎo)致的內(nèi)存數(shù)據(jù)丟失得以恢復(fù)与帆;
  • Immutable Memtable:達(dá)到Memtable設(shè)置的容量上限后,Memtable會(huì)變?yōu)镮mmutable為之后向SST文件的歸并做準(zhǔn)備勿她,顧名思義茶凳,Immutable Mumtable不再接受用戶寫入,同時(shí)會(huì)有新的Memtable生成筒狠;
  • SST文件:磁盤數(shù)據(jù)存儲(chǔ)文件。分為L(zhǎng)evel 0到Level N多層辩恼,每一層包含多個(gè)SST文件谓形;單層SST文件總量隨層次增加成倍增長(zhǎng);文件內(nèi)數(shù)據(jù)有序聘萨;其中Level0的SST文件由Immutable直接Dump產(chǎn)生,其他Level的SST文件由其上一層的文件和本層文件歸并產(chǎn)生米辐;SST文件在歸并過(guò)程中順序?qū)懮桑珊髢H可能在之后的歸并中被刪除翘贮,而不會(huì)有任何的修改操作。
  • Manifest文件: Manifest文件中記錄SST文件在不同Level的分布锨能,單個(gè)SST文件的最大最小key芍耘,以及其他一些LevelDB需要的元信息。
  • Current文件: 從上面的介紹可以看出齿穗,LevelDB啟動(dòng)時(shí)的首要任務(wù)就是找到當(dāng)前的Manifest,而Manifest可能有多個(gè)跺株。Current文件簡(jiǎn)單的記錄了當(dāng)前Manifest的文件名脖卖,從而讓這個(gè)過(guò)程變得非常簡(jiǎn)單。

寫流程簡(jiǎn)析

了解了整體流程和架構(gòu)后袖扛,我們分析兩個(gè)基本的流程,也就是LevelDB的寫流程和讀流程蛆封。我們這里首先分析一下寫流程勾栗,畢竟要先有數(shù)據(jù)后才能讀數(shù)據(jù)。
LevelDB的寫操作包括設(shè)置key-value和刪除key兩種砸讳。需要指出的是這兩種情況在LevelDB的處理上是一致的界牡,刪除操作其實(shí)是向LevelDB插入一條標(biāo)識(shí)為刪除的數(shù)據(jù)。下面我們先看一下LevelDB插入值的整體流程宿亡,具體如圖4所示。


圖4 LevelDB寫數(shù)據(jù)流程

具體代碼請(qǐng)自行閱讀烈钞,本文不貼過(guò)多的代碼。這里需要重點(diǎn)說(shuō)明的是DBImpl::Write函數(shù),如圖5是該函數(shù)的代碼片段臭脓,從這段代碼中我們可以很清楚的看到數(shù)據(jù)被分別寫入日志和內(nèi)存2個(gè)地方。其它代碼都比較簡(jiǎn)單来累,大家請(qǐng)自行對(duì)照流程圖閱讀。


圖5 DBImpl::Write代碼片段

讀流程簡(jiǎn)析

讀流程要比寫流程簡(jiǎn)單一些葫录,核心代碼邏輯如圖6所示米同。首先摔竿,生成內(nèi)部查詢所用的Key,該Key是由用戶請(qǐng)求的UserKey拼接上Sequence生成的熬苍。其中Sequence可以用戶提供或使用當(dāng)前最新的Sequence,LevelDB可以保證僅查詢?cè)谶@個(gè)Sequence之前的寫入柴底。然后粱胜,用生成的Key,依次嘗試從 Memtable凿歼,Immtable以及SST文件中讀取,直到找到答憔。

圖6 LevelDB讀流程
  • 從SST文件中查找需要依次嘗試在每一層中讀取虐拓,得益于Manifest中記錄的每個(gè)文件的key區(qū)間傲武,我們可以很方便的知道某個(gè)key是否在文件中城榛。Level0的文件由于直接由Immutable Dump 產(chǎn)生,不可避免的會(huì)相互重疊狠持,所以需要對(duì)每個(gè)文件依次查找瞻润。對(duì)于其他層次,由于歸并過(guò)程保證了其互相不重疊且有序绍撞,二分查找的方式提供了更好的查詢效率。
  • 可以看出同一個(gè)Key出現(xiàn)在上層的操作會(huì)屏蔽下層的章贞。也因此刪除Key時(shí)只需要在Memtable壓入一條標(biāo)記為刪除的條目即可非洲。被其屏蔽的所有條目會(huì)在之后的歸并過(guò)程中清除。

好了里覆,今天就先到這缆瓣,后續(xù)我們?cè)谏钊氲慕榻BLevelDB的其它部分的,并且逐步深入隧甚,理解其內(nèi)部的精髓渡冻。

關(guān)注微信公眾號(hào),獲取信息更及時(shí): itworld123

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帽借,一起剝皮案震驚了整個(gè)濱河市超歌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脆荷,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梦皮,死亡現(xiàn)場(chǎng)離奇詭異桃焕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)退子,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)荐虐,“玉大人,你說(shuō)我怎么就攤上這事福扬。” “怎么了狠裹?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵汽烦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我俗冻,道長(zhǎng)牍颈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任煮岁,我火速辦了婚禮讥蔽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘画机。我一直安慰自己冶伞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布色罚。 她就那樣靜靜地躺著碰缔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戳护。 梳的紋絲不亂的頭發(fā)上金抡,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天瀑焦,我揣著相機(jī)與錄音,去河邊找鬼梗肝。 笑死,一個(gè)胖子當(dāng)著我的面吹牛禀晓,可吹牛的內(nèi)容都是我干的粹懒。 我是一名探鬼主播凫乖,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼帽芽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼导街!你這毒婦竟也來(lái)了搬瑰?” 一聲冷哼從身側(cè)響起跌捆,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤佩厚,失蹤者是張志新(化名)和其女友劉穎抄瓦,沒想到半個(gè)月后钙姊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埂伦,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膊毁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年描焰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荆秦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片步绸。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡靡努,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出漓概,到底是詐尸還是另有隱情病梢,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布觅彰,位于F島的核電站填抬,受9級(jí)特大地震影響飒责,放射性物質(zhì)發(fā)生泄漏宏蛉。R本人自食惡果不足惜性置,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一嗅义、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧西采,春花似錦械馆、人聲如沸霹崎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)默赂。三九已至缆八,卻和暖如春奈辰,著一層夾襖步出監(jiān)牢的瞬間乱豆,已是汗流浹背咙鞍。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工翰守, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜡峰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓载绿,卻偏偏與公主長(zhǎng)得像崭庸,于是被迫代替她去往敵國(guó)和親怕享。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镰踏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • LevelDB是Google傳奇工程師Jeff Dean和Sanjay Ghemawat開源的KV存儲(chǔ)引擎奠伪,無(wú)論從...
    CatKang閱讀 4,841評(píng)論 5 25
  • 【轉(zhuǎn)自】http://alinuxer.sinaapp.com/?p=400 LDB 首先绊率,我們先總結(jié)下googl...
    lxqfirst閱讀 7,949評(píng)論 0 2
  • 版本控制或元信息管理佣盒,是LevelDB中比較重要的內(nèi)容。本文首先介紹其在整個(gè)LevelDB中不可替代的作用紊搪;之后從...
    CatKang閱讀 5,486評(píng)論 12 12
  • # LevelDB簡(jiǎn)單介紹 ------ LevelDB是Google開源的持久化KV單機(jī)數(shù)據(jù)庫(kù)耀石,具有很高的隨機(jī)寫...
    ClimbYang閱讀 528評(píng)論 0 0
  • CT Walk of Shame Givenchy 311 312 103 318 Dior 772 080 雅詩(shī)...
    SeoMR96閱讀 100評(píng)論 0 0