幾種主流NoSQL資料庫的比較
鑑於缺乏專案中的實戰經驗沉澱,本文內容和觀點主要還是從各平臺資料蒐羅彙總,也不會有太多深入或底層原理探討。
本文所引用的資料來源將示於本文尾部。所彙總的內容僅供參考,若有異議望指正。
HBase
HBase 是 Apache Hadoop 中的一個子專案,屬於 bigtable 的開源版本,所實現的語言為Java(故依賴 Java SDK)。HBase 依託於 Hadoop 的 HDFS(分散式檔案系統)作為最基本儲存基礎單元。
HBase在列上實現了 BigTable 論文提到的壓縮演算法、記憶體操作和布隆過濾器。HBase的表能夠作為 MapReduce 任務的輸入和輸出,可以通過Java API來訪問資料,也可以通過REST、Avro或者Thrift的API來訪問。
1.1 資料格式
HBash 的資料儲存是基於列(ColumnFamily)的,且非常鬆散—— 不同於傳統的關係型資料庫(RDBMS),HBase 允許表下某行某列值為空時不做任何儲存(也不佔位),減少了空間佔用也提高了讀效能。
不過鑑於其它NoSql資料庫也具有同樣靈活的資料儲存結構,該優勢在本次選型中並不出彩。我們以一個簡單的例子來了解使用 RDBMS 和 HBase 各自的解決方式:
⑴ RDBMS方案:
其中Article表格式:
Author表格式:
⑵ 等價的HBase方案:
對於前端而言,這裡的 Column Keys 和 Column Family 可以看為這樣的關係:
columId1 = { //id=1的行 article: { //ColumnFamily-article title: XXX, //ColumnFamily-article下的key之一 content: XXX, tags: XXX }, author: { //ColumnFamily-author name: XXX nickname: XXX } }
1.2 效能
HStore儲存是HBase儲存的核心,它由兩部分組成,一部分是MemStore,一部分是StoreFiles。
MemStore 是 Sorted Memory Buffer,使用者寫入的資料首先會放入MemStore,當MemStore滿了以後會Flush成一個StoreFile(底層實現是HFile),當StoreFile檔案數量增長到一定閾值,會觸發Compact合併操作,將多個StoreFiles合併成一個StoreFile,合併過程中會進行版本合併和資料刪除,因此可以看出HBase其實只有增加資料,所有的更新和刪除操作都是在後續的compact過程中進行的,這使得使用者的寫操作只要進入記憶體中就可以立即返回,保證了HBase I/O的高效能。
1.3 資料版本
Hbase 還能直接檢索到往昔版本的資料,這意味著我們更新資料時,舊資料並沒有即時被清除,而是保留著:
Hbase 中通過 row+columns 所指定的一個存貯單元稱為cell。每個 cell都儲存著同一份資料的多個版本——版本通過時間戳來索引。
時間戳的型別是 64位整型。時間戳可以由Hbase(在資料寫入時自動 )賦值,此時時間戳是精確到毫秒的當前系統時間。時間戳也可以由客戶顯式賦值。如果應用程式要避免資料版本衝突,就必須自己生成具有唯一性的時間戳。每個 cell中,不同版本的資料按照時間倒序排序,即最新的資料排在最前面。
為了避免資料存在過多版本造成的的管理 (包括存貯和索引)負擔,Hbase提供了兩種資料版本回收方式。一是儲存資料的最後n個版本,二是儲存最近一段時間內的版本(比如最近七天)。使用者可以針對每個列族進行設定。
1.4 CAP類別
屬於CP型別(瞭解更多)。2. Node下的使用
HBase的相關操作可參考下表:
在node環境下,可通過 node-hbase 來實現相關訪問和操作,注意該工具包依賴於 PHYTHON2.X(3.X不支援)和Coffee。
如果是在 window 系統下還需依賴 .NET framwork2.0,64位系統可能無法直接通過安裝包安裝。
官方示例:
var assert = require('assert'); var hbase = require('hbase'); hbase({ host: '127.0.0.1', port: 8080 }) .table('my_table' ) //建立一個Column Family .create('my_column_family', function(err, success){ this.row('my_row') //定位到指定行 .put('my_column_family:my_column', 'my value', function(err, success){ this.get('my_column_family', function(err, cells){ this.exists(function(err, exists){ assert.ok(exists); }); }); }); });
資料檢索:
client .table('node_table') .scan({ startRow: 'my_row', //起始行 maxVersions: 1 //版本 }, function(err, rows){ console.log(err, rows); });
另有 hbase-client 也是一個不錯的選擇,具體API參照其文件。
3. 優缺點
優勢
1. 儲存容量大,一個表可以容納上億行,上百萬列;
2. 可通過版本進行檢索,能搜到所需的歷史版本資料;
3. 負載高時,可通過簡單的新增機器來實現水平切分擴充套件,跟Hadoop的無縫整合保障了其資料可靠性(HDFS)和海量資料分析的高效能(MapReduce);
4. 在第3點的基礎上可有效避免單點故障的發生。
缺點
1. 基於Java語言實現及Hadoop架構意味著其API更適用於Java專案;
2. node開發環境下所需依賴項較多、配置麻煩(或不知如何配置,如持久化配置),缺乏文件;
3. 佔用記憶體很大,且鑑於建立在為批量分析而優化的HDFS上,導致讀取效能不高;
4. API相比其它 NoSql 的相對笨拙。
適用場景
1. bigtable型別的資料儲存;
2. 對資料有版本查詢需求;
3. 應對超大資料量要求擴充套件簡單的需求。
Redis
Redis 是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。目前由VMware主持開發工作。1. 特點
1.1 資料格式
Redis 通常被稱為資料結構伺服器,因為值(value)可以是 字串(String), 雜湊(Hash/Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)五種型別,操作非常方便。比如,如果你在做好友系統,檢視自己的好友關係,如果採用其他的key-value系統,則必須把對應的好友拼接成字串,然後在提取好友時,再把value進行解析,而redis則相對簡單,直接支援list的儲存(採用雙向連結串列或者壓縮連結串列的儲存方式)。我們來看下這五種資料型別。
⑴ String
- string 是 Redis 最基本的型別,你可以理解成與 Memcached 一模一樣的型別,一個key對應一個value。
- string 型別是二進位制安全的。意思是 Redis 的 string 可以包含任何資料。比如 jpg 圖片或者序列化的物件 。
- string 型別是 Redis 最基本的資料型別,一個鍵最大能儲存512MB。
例項:
redis 127.0.0.1:6379> SET name zfpx OK redis 127.0.0.1:6379> GET name "zfpx"
在以上例項中我們使用了 Redis 的 SET 和 GET 命令。鍵為 name,對應的值為"zfpx"。 注意:一個鍵最大能儲存512MB。
⑵ Hash
- Redis hash 是一個鍵值對集合。
- Redis hash 是一個 string 型別的 field 和 value 的對映表,hash 特別適合用於儲存物件。
例項:
redis 127.0.0.1:6379> HMSET user:1 username zfpx password 123 OK redis 127.0.0.1:6379> HGETALL user:1 1) "username" 2) "zfpx" 3) "password" 4) "123"
以上例項中 hash 資料型別儲存了包含使用者指令碼資訊的使用者物件。 例項中我們使用了 Redis HMSET, HGETALL 命令,user:1 為鍵值。 每個 hash 可以儲存 232 - 1 鍵值對(40多億)。
⑶ List
Redis 列表是簡單的字串列表,按照插入順序排序。你可以新增一個元素導列表的頭部(左邊)或者尾部(右邊)。
例項:
redis 127.0.0.1:6379> lpush name zfpx1 (integer) 1 redis 127.0.0.1:6379> lpush name zfpx2 (integer) 2 redis 127.0.0.1:6379> lpush name zfpx3 (integer) 3 redis 127.0.0.1:6379> lrange name 0 -1 1) "zfpx3" 2) "zfpx2" 3) "zfpx1"
列表最多可儲存 232 - 1 元素 (4294967295, 每個列表可儲存40多億)。
⑷ Sets
Redis的Set是string型別的無序集合。 集合是通過雜湊表實現的,所以新增,刪除,查詢的複雜度都是O(1)。
新增一個string元素到 key 對應的 set 集合中,成功返回1,如果元素已經在集合中返回0,key對應的set不存在返回錯誤,指令格式為
sadd key member
例項:
redis 127.0.0.1:6379> sadd school zfpx1 (integer) 1 redis 127.0.0.1:6379> sadd school zfpx1 (integer) 0 redis 127.0.0.1:6379> sadd school zfpx2 (integer) 1 redis 127.0.0.1:6379> sadd school zfpx2 (integer) 0 redis 127.0.0.1:6379> smembers school 1) "zfpx1" 2) "zfpx2"
注意:以上例項中 zfpx1 添加了兩次,但根據集合內元素的唯一性,第二次插入的元素將被忽略。 集合中最大的成員數為 232 - 1 (4294967295, 每個集合可儲存40多億個成員)。
⑸ sorted sets/zset
Redis zset 和 set 一樣也是string型別元素的集合,且不允許重複的成員。 不同的是每個元素都會關聯一個double型別的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(score)卻可以重複。可以通過 zadd 命令(格式如下) 新增元素到集合,若元素在集合中存在則更新對應score
zadd key score member
例項:
redis 127.0.0.1:6379> zadd school 0 zfpx1 (integer) 1 redis 127.0.0.1:6379> zadd school 2 zfpx2 (integer) 1 redis 127.0.0.1:6379> zadd school 0 zfpx3 (integer) 1 redis 127.0.0.1:6379> zadd school 1 zfpx4 (integer) 0 redis 127.0.0.1:6379> ZRANGEBYSCORE school 0 100 1) "zfpx1" 2) "zfpx3" 3) "zfpx4" 4) "zfpx2"
1.2 效能
Redis資料庫完全在記憶體中,因此處理速度非常快,每秒能執行約11萬集合,每秒約81000+條記錄(測試資料的可參考這篇《
Redis的資料能確保一致性——所有Redis操作是原子性(Atomicity,意味著操作的不可再分,要麼執行要麼不執行)的,這保證瞭如果兩個客戶端同時訪問的Redis伺服器將獲得更新後的值。
1.3 持久化
通過定時快照(snapshot)和基於語句的追加(AppendOnlyFile,aof)兩種方式,redis可以支援資料持久化——將記憶體中的資料儲存到磁碟上,方便在宕機等突發情況下快速恢復。
1.4 CAP類別
屬於CP型別(瞭解更多)。
2. Node下的使用
node 下可使用
var redis = require("redis"), client = redis.createClient(); // if you'd like to select database 3, instead of 0 (default), call // client.select(3, function() { /* ... */ }); client.on("error", function (err) { console.log("Error " + err); }); client.set("string key", "string val", redis.print); client.hset("hash key", "hashtest 1", "some value", redis.print); client.hset(["hash key", "hashtest 2", "some other value"], redis.print); client.hkeys("hash key", function (err, replies) { console.log(replies.length + " replies:"); replies.forEach(function (reply, i) { console.log(" " + i + ": " + reply); }); client.quit(); });
3. 優缺點
優勢
1. 非常豐富的資料結構;
2. Redis提供了事務的功能,可以保證一串 命令的原子性,中間不會被任何操作打斷;
3. 資料存在記憶體中,讀寫非常的高速,可以達到10w/s的頻率。
缺點
1. Redis3.0後才出來官方的叢集方案,但仍存在一些架構上的問題(出處);
2. 持久化功能體驗不佳——通過快照方法實現的話,需要每隔一段時間將整個資料庫的資料寫到磁碟上,代價非常高;而aof方法只追蹤變化的資料,類似於mysql的binlog方法,但追加log可能過大,同時所有操作均要重新執行一遍,恢復速度慢;
3. 由於是記憶體資料庫,所以,單臺機器,儲存的資料量,跟機器本身的記憶體大小。雖然redis本身有key過期策略,但是還是需要提前預估和節約記憶體。如果記憶體增長過快,需要定期刪除資料。
適用場景
適用於資料變化快且資料庫大小可遇見(適合記憶體容量)的應用程式。更具體的可參照這篇《Redis 的 5 個常見使用場景》譯文。
MongoDB
MongoDB 是一個高效能,開源,無模式的文件型資料庫,開發語言是C++。它在許多場景下可用於替代傳統的關係型資料庫或鍵/值儲存方式。
1.特點
1.1 資料格式
在 MongoDB 中,文件是對資料的抽象,它的表現形式就是我們常說的 BSON(Binary JSON )。
BSON 是一個輕量級的二進位制資料格式。MongoDB 能夠使用 BSON,並將 BSON 作為資料的儲存存放在磁碟中。
BSON 是為效率而設計的,它只需要使用很少的空間,同時其編碼和解碼都是非常快速的。即使在最壞的情況下,BSON格式也比JSON格式再最好的情況下儲存效率高。
對於前端開發者來說,一個“文件”就相當於一個物件:
{“name":"mengxiangyue","sex":"nan"}
對於文件是有一些限制的:有序、區分大小寫的,所以下面的兩個文件是與上面不同的:
{”sex“:"nan","name":"mengxiangyue"}
{"Name":"mengxiangyue","sex":"nan"}
另外,對於文件的欄位 MongoDB 有如下的限制:
_id必須存在,如果你插入的文件中沒有該欄位,那麼 MongoDB 會為該文件建立一個ObjectId作為其值。_id的值必須在本集合中是唯一的。
多個文件則組合為一個“集合”。在 MongoDB 中的集合是無模式的,也就是說集合中儲存的文件的結構可以是不同的,比如下面的兩個文件可以同時存入到一個集合中:
{"name":"mengxiangyue"}
{"Name":"mengxiangyue","sex":"nan"}
1.2 效能
MongoDB 目前支援的儲存引擎為記憶體對映引擎。當 MongoDB 啟動的時候,會將所有的資料檔案對映到記憶體中,然後作業系統會託管所有的磁碟操作。這種儲存引擎有以下幾種特點:
* MongoDB 中關於記憶體管理的程式碼非常精簡,畢竟相關的工作已經有作業系統進行託管。
* MongoDB 伺服器使用的虛擬記憶體將非常巨大,並將超過整個資料檔案的大小。不用擔心,作業系統會去處理這一切。
在《Mongodb億級資料量的效能測試》一文中,MongoDB 展現了強勁的大資料處理效能(資料甚至比Redis的漂亮的多)。
另外,MongoDB 提供了全索引支援:包括文件內嵌物件及陣列。Mongo的查詢優化器會分析查詢表示式,並生成一個高效的查詢計劃。通常能夠極大的提高查詢的效率。
1.3 持久化
MongoDB 在1.8版本之後開始支援 journal,就是我們常說的 redo log,用於故障恢復和持久化。
當系統啟動時,MongoDB 會將資料檔案對映到一塊記憶體區域,稱之為Shared view,在不開啟 journal 的系統中,資料直接寫入shared view,然後返回,系統每60s重新整理這塊記憶體到磁碟,這樣,如果斷電或down機,就會丟失很多記憶體中未持久化的資料。
當系統開啟了 journal 功能,系統會再對映一塊記憶體區域供 journal 使用,稱之為 private view,MongoDB 預設每100ms重新整理 privateView 到 journal,也就是說,斷電或宕機,有可能丟失這100ms資料,一般都是可以忍受的,如果不能忍受,那就用程式寫log吧(但開啟journal後使用的虛擬記憶體是之前的兩倍)。
1.4 CAP類別
MongoDB 比較靈活,可以設定成 strong consistent (CP型別)或者 eventual consistent(AP型別)。
但其預設是 CP 型別(瞭解更多)。
2. Node下的使用
MongoDB 在 node 環境下的驅動引擎是 ,作為依賴封裝到 mongodb 包裡,我們直接安裝即可:
npm install mongodb
例項:
var mongodb = require('mongodb'); var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 }); var db = new mongodb.Db('mydb', mongodbServer); /* open db */ db.open(function() { /* Select 'contact' collection */ db.collection('contact', function(err, collection) { /* Insert a data */ collection.insert({ name: 'Fred Chien', email: '[email protected]', tel: [ '0926xxx5xx', '0912xx11xx' ] }, function(err, data) { if (data) { console.log('Successfully Insert'); } else { console.log('Failed to Insert'); } }); /* Querying */ collection.find({ name: 'Fred Chien' }, function(err, data) { /* Found this People */ if (data) { console.log('Name: ' + data.name + ', email: ' + data.email); } else { console.log('Cannot found'); } }); }); });
另外我們也可以使用MongoDB的ODM(面向物件資料庫管理器) ——mongoose 來做資料庫管理,具體參照其API文件。
3. 優缺點
優勢
1. 強大的自動化 shading 功能(更多戳這裡);
2. 全索引支援,查詢非常高效;
3. 面向文件(BSON)儲存,資料模式簡單而強大。
4. 支援動態查詢,查詢指令也使用JSON形式的標記,可輕易查詢文件中內嵌的物件及陣列。
5. 支援 javascript 表示式查詢,可在伺服器端執行任意的 javascript函式。
缺點
1. 單個文件大小限制為16M,32位系統上,不支援大於2.5G的資料;
2. 對記憶體要求比較大,至少要保證熱資料(索引,資料及系統其它開銷)都能裝進記憶體;
3. 非事務機制,無法保證事件的原子性。
適用場景
1. 適用於實時的插入、更新與查詢的需求,並具備應用程式實時資料儲存所需的複製及高度伸縮性;
2. 非常適合文件化格式的儲存及查詢;
3. 高伸縮性的場景:MongoDB 非常適合由數十或者數百臺伺服器組成的資料庫。
4. 對效能的關注超過對功能的要求。
Couchbase
本文之所以沒有介紹 CouchDB 或 Membase,是因為它們合併了。合併之後的公司基於 Membase 與 CouchDB 開發了一款新產品,新產品的名字叫做 Couchbase。
Couchbase 可以說是集合眾家之長,目前應該是最先進的Cache系統,其開發語言是 C/C++。
Couchbase Server 是個面向文件的資料庫(其所用的技術來自於Apache CouchDB專案),能夠實現水平伸縮,並且對於資料的讀寫來說都能提供低延遲的訪問(這要歸功於Membase技術)。
1.特點
1.1 資料格式
Couchbase 跟 MongoDB 一樣都是面向文件的資料庫,不過在往 Couchbase 插入資料前,需要先建立 bucket —— 可以把它理解為“庫”或“表”。
因為 Couchbase 資料基於 Bucket 而導致缺乏表結構的邏輯,故如果需要查詢資料,得先建立 view(跟RDBMS的檢視不同,view是將資料轉換為特定格式結構的資料形式如JSON)來執行。
Bucket的意義 —— 在於將資料進行分隔,比如:任何 view 就是基於一個 Bucket 的,僅對 Bucket 內的資料進行處理。一個server上可以有多個Bucket,每個Bucket的儲存型別、內容佔用、資料複製數量等,都需要分別指定。從這個意義上看,每個Bucket都相當於一個獨立的例項。在叢集狀態下,我們需要對server進行叢集設定,Bucket只側重資料的保管。
每當views建立時, 就會建立indexes, index的更新和以往的資料庫索引更新區別很大。 比如現在有1W資料,更新了200條,索引只需要更新200條,而不需要更新所有資料,map/reduce功能基於index的懶更新行為,大大得益。
要留意的是,對於所有檔案,couchbase 都會建立一個額外的 56byte 的 metadata,這個 metadata 功能之一就是表明資料狀態,是否活動在記憶體中。同時檔案的 key 也作為識別符號和 metadata 一起長期活動在記憶體中。
1.2 效能
couchbase 的精髓就在於依賴記憶體最大化降低硬碟I/O對吞吐量的負面影響,所以其讀寫速度非常快,可以達到亞毫秒級的響應。
couchbase在對資料進行增刪時會先體現在記憶體中,而不會立刻體現在硬碟上,從記憶體的修改到硬碟的修改這一步驟是由 couchbase 自動完成,等待執行的硬碟操作會以write queue的形式排隊等待執行,也正是通過這個方法,硬碟的I/O效率在 write queue 滿之前是不會影響 couchbase 的吞吐效率的。
鑑於記憶體資源肯定遠遠少於硬碟資源,所以如果資料量小,那麼全部資料都放在記憶體上自然是最優選擇,這時候couchbase的效率也是異常高。
但是資料量大的時候過多的資料就會被放在硬碟之中。當然,最終所有資料都會寫入硬碟,不過有些頻繁使用的資料提前放在記憶體中自然會提高效率。
1.3 持久化
其前身之一 memcached 是完全不支援持久化的,而 Couchbase 添加了對非同步持久化的支援:
Couchbase提供兩種核心型別的buckets —— Couchbase 型別和 Memcached 型別。其中 Couchbase 型別提供了高可用和動態重配置的分散式資料儲存,提供持久化儲存和複製服務。
Couchbase bucket 具有永續性 —— 資料單元非同步從記憶體寫往磁碟,防範服務重啟或較小的故障發生時資料丟失。永續性屬性是在 bucket 級設定的。
1.4 CAP型別
Couchbase 群集所有點都是對等的,只是在建立群或者加入叢集時需要指定一個主節點,一旦結點成功加入叢集,所有的結點對等。
對等網的優點是,叢集中的任何節點失效,叢集對外提供服務完全不會中斷,只是叢集的容量受影響。
由於 couchbase 是對等網叢集,所有的節點都可以同時對客戶端提供服務,這就需要有方法把叢集的節點資訊暴露給客戶端,couchbase 提供了一套機制,客戶端可以獲取所有節點的狀態以及節點的變動,由客戶端根據叢集的當前狀態計算 key 所在的位置。
就上述的介紹,Couchbase 明顯屬於 CP 型別。
2. Node下的使用
例項:
var couchbase = require("couchbase"); var bucket = new couchbase.Connection({ 'bucket':'beer-sample', 'host':'127.0.0.1:8091' }, function(err) { if (err) { // Failed to make a connection to the Couchbase cluster. throw err; } // 獲取文件 bucket.get('aass_brewery-juleol', function(err, result) { if (err) { // Failed to retrieve key throw err; } var doc = result.value; console.log(doc.name + ', ABV: ' + doc.abv); doc.comment = "Random beer from Norway"; bucket.replace('aass_brewery-juleol', doc, function(err, result) { if (err) { // Failed to replace key throw err; } console.log(result); // Success! process.exit(0); }); }); });
3. 優缺點
優勢
1. 高併發性,高靈活性,高拓展性,容錯性好;
2. 以 vBucket 的概念實現更理想化的自動分片以及動態擴容(瞭解更多);
缺點
1. Couchbase 的儲存方式為 Key/Value,但 Value 的型別很為單一,不支援陣列。另外也不會自動建立doc id,需要為每一文件指定一個用於儲存的 Document Indentifer;
2. 各種元件拼接而成,都是c++實現,導致複雜度過高,遇到奇怪的效能問題排查比較困難,(中文)文件比較欠缺;
3. 採用快取全部key的策略,需要大量記憶體。節點宕機時 failover 過程有不可用時間,並且有部分資料丟失的可能,在高負載系統上有假死現象;
4. 逐漸傾向於閉源,社群版本(免費,但不提供官方維護升級)和商業版本之間差距比較大。
適用場景
1. 適合對讀寫速度要求較高,但伺服器負荷和記憶體花銷可遇見的需求;
2. 需要支援 memcached 協議的需求。
LevelDB
LevelDB 是由谷歌重量級工程師(Jeff Dean 和 Sanjay Ghemawat)開發的開源專案,它是能處理十億級別規模 key-value 型資料永續性儲存的程式庫,開發語言是C++。
除了永續性儲存,LevelDB 還有一個特點是 —— 寫效能遠高於讀效能(當然讀效能也不差)。
1.特點
LevelDB 作為儲存系統,資料記錄的儲存介質包括記憶體以及磁碟檔案,當LevelDB運行了一段時間,此時我們給LevelDb進行透視拍照,那麼您會看到如下一番景象:
(圖1)
LevelDB 所寫入的資料會先插入到記憶體的 Mem Table 中,再由 Mem Table 合併到只讀且鍵值有序的 Disk Table(SSTable) 中,再由後臺執行緒不時的對 Disk Table 進行歸併。
記憶體中存在兩個 Mem Table —— 一個是可以往裡面寫資料的table A,另一個是正在合併到硬碟的 table B。
Mem Table 用 skiplist 實現,寫資料時,先寫日誌(.log),再往A插入,因為一次寫入操作只涉及一次磁碟順序寫和一次記憶體寫入,所以這是為何說LevelDb寫入速度極快的主要原因。如果當B還沒完成合並,而A已經寫滿時,寫操作必須等待。
DiskTable(SSTable,格式為.sst)是分層的(leveldb的名稱起源),每一個大小不超過2M。最先 dump 到硬碟的 SSTable 的層級為0,層級為0的 SSTable 的鍵值範圍可能有重疊。如果這樣的 SSTable 太多,那麼每次都需要從多個 SSTable 讀取資料,所以LevelDB 會在適當的時候對 SSTable 進行 Compaction,使得新生成的 SSTable 的鍵值範圍互不重疊。
進行對層級為 level 的 SSTable 做 Compaction 的時候,取出層級為 level+1 的且鍵值空間與之重疊的 Table,以順序掃描的方式進行合併。level 為0的 SSTable 做 Compaction 有些特殊:會取出 level 0 所有重疊的Table與下一層做 Compaction,這樣做保證了對於大於0的層級,每一層裡 SSTable 的鍵值空間是互不重疊的。
SSTable 中的某個檔案屬於特定層級,而且其儲存的記錄是 key 有序的,那麼必然有檔案中的最小 key 和最大 key,這是非常重要的資訊,LevelDB 應該記下這些資訊 —— Manifest 就是幹這個的,它記載了 SSTable 各個檔案的管理資訊,比如屬於哪個Level,檔名稱叫啥,最小 key 和最大 key 各自是多少。下圖是 Manifest 所儲存內容的示意:
圖中只顯示了兩個檔案(Manifest 會記載所有 SSTable 檔案的這些資訊),即 Level0 的 Test1.sst 和 Test2.sst 檔案,同時記載了這些檔案各自對應的 key 範圍,比如 Test1.sstt 的 key 範圍是“an”到 “banana”,而檔案 Test2.sst 的 key 範圍是“baby”到“samecity”,可以看出兩者的 key 範圍是有重疊的。
那麼上方圖1中的 Current 檔案是幹什麼的呢?這個檔案的內容只有一個資訊,就是記載當前的 Manifest 檔名。因為在 LevleDB 的執行過程中,隨著 Compaction 的進行,SSTable 檔案會發生變化,會有新的檔案產生,老的檔案被廢棄,Manifest 也會跟著反映這種變化,此時往往會新生成 Manifest 檔案來記載這種變化,而 Current 則用來指出哪個 Manifest 檔案才是我們關心的那個 Manifest 檔案。
注意,鑑於 LevelDB 不屬於分散式資料庫,故CAP法則在此處不適用。
2. Node下的使用
Node 下可以使用 LevelUP 來操作 LevelDB 資料庫:
var levelup = require('levelup') // 1) Create our database, supply location and options. // This will create or open the underlying LevelDB store. var db = levelup('./mydb') // 2) put a key & value db.put('name', 'LevelUP', function (err) { if (err) return console.log('Ooops!', err) // some kind of I/O error // 3) fetch by key db.get('name', function (err, value) { if (err) return console.log('Ooops!', err) // likely the key was not found // ta da! console.log('name=' + value) }) })
LevelUp 的API非常簡潔實用,具體可參考官方文件。
3. 優缺點
優勢
1. 操作介面簡單,基本操作包括寫記錄,讀記錄和刪除記錄,也支援針對多條操作的原子批量操作;
2. 寫入效能遠強於讀取效能,
3. 資料量增大後,讀寫效能下降趨平緩。
缺點
1. 隨機讀效能一般;
2. 對分散式事務的支援還不成熟。而且機器資源浪費率高。
適應場景
適用於對寫入需求遠大於讀取需求的場景(大部分場景其實都是這樣)。
References
hbase快速入門 —— http://wangmored.iteye.com/blog/1727731
8種 NoSQL 資料庫系統對比 —— http://blog.jobbole.com/1344/
node-hbase —— https://github.com/wdavidw/node-hbase
HBase 超詳細介紹 —— http://blog.csdn.net/frankiewang008/article/details/41965543
HBase 將主導 NoSQL 嗎 —— http://www.oschina.net/translate/big-data-debate-will-hbase-dominate-nosq
memcached,redis,mongodb的區別以及優缺點 —— http://blog.csdn.net/senssic/article/details/30511543redis的優點和缺點 —— http://joezhengjinhong.blog.51cto.com/7791846/1565754
redis入門 (一)認識redis(該文章有部分示例不正確,引用時做了修正) —— http://www.zhufengpeixun.cn/jishuziliao/Nodejishuziliao/2015-11-23/410.htmlMongoDB文件、集合、資料庫概念 —— http://blog.csdn.net/mengxiangyue/article/details/9879925
mongodb 持久化(5) —— http://ju.outofmemory.cn/entry/81554
關於Mongodb的全面總結 —— http://blog.csdn.net/shellching/article/details/7651979
Couchbase的簡單介紹 —— http://bbs.byr.cn/#!article/Database/8365
Memcache升級版:CouchBase(一)安裝篇 —— http://blog.hackroad.com/operations-engineer/linux_server/8380.html
Couchbase介紹,更好的Cache系統 —— http://zhang.hu/couchbase/
Couchbase第一印象(架構特性) —— http://www.bubuko.com/infodetail-550423.html
NoSQL選型詳解 —— http://www.thebigdata.cn/JieJueFangAn/6476.html
資料分析與處理之二(Leveldb 實現原理)—— http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html
訊息中介軟體剖析 —— http://blog.lday.me/?p=170
相關推薦
幾種主流NoSQL資料庫的比較
鑑於缺乏專案中的實戰經驗沉澱,本文內容和觀點主要還是從各平臺資料蒐羅彙總,也不會有太多深入或底層原理探討。 本文所引用的資料來源將示於本文尾部。所彙總的內容僅供參考,若有異議望指正。 HBase HBase 是 Apache Hadoop 中的一個子專案,屬於 bigtable 的開源版本,所實現的語言為
幾款主流 NoSQL 資料庫的對比
最近小組準備啟動一個 node 開源專案,從前端親和力、大資料下的IO效能、可擴充套件性幾點入手挑選了 NoSql 資料庫,但具體使用哪一款產品還需要做一次選型。 我們最終把選項範圍縮窄在 HBase、Redis、MongoDB、Couchbase、LevelDB
Android中幾種主流網路框架比較
引言 目前網路請求框架也比較多,本文針對封裝的比較完善的Volley,Okhttp,Retrofit,AsyncHttpClient研究比較了,才知道選擇哪個最適合。 一.Volley 1.Volley主要特點 1. 擴充套件性強
幾種主流資料庫比較之我們該學習哪種資料庫
該帖子是我師傅的傑作,僅供參考(個人推崇MySQL)! 基礎知識 不管你想選擇哪種資料庫產品,有些基礎理論知識必須打紮實,尤其是:資料庫系統概論、Linux作業系統、SQL標準語言、資料結構(重點排序演算法)、開發語言(至少懂幾款指令碼語言,SHELL必須要會,其次最好能再掌握一種指令碼語言,例如:PHP
主流的幾種推送以及比較
百度雲推送點評:百度雲推送可謂為使用者體驗而生,它實現了多項創新,並通過百度各大產品線千萬級連 接的可用性測試,迅速成為國內第三方雲推送平臺的標杆。據瞭解,在百度雲推送正式釋出之前,大部分的百度產品其實都已在使用百度雲推送,例如百度框、百度 網盤、百度地圖、百度視訊,已覆蓋
幾種 ETL 工具的比較(Kettle,Talend,Informatica 等)
調整 都是 acl 項目 talend 插件 str 操作 優化 成本: 軟件 成本包括多方面,主要包括軟件產品, 售前培訓, 售後咨詢, 技術 支持等。 開源 產品本身是免費的,成本主要是培訓和咨詢,所以成本會一直維持在一個較低水平。 商業產品本身價格很高,但是一般會提供
SQL Server中幾種遍歷方式比較
不同 .com font size 常用 分享 分享圖片 遊標 inf SQL遍歷解析 在SQL的存儲過程,函數中,經常需要使用遍歷(遍歷table),其中遊標、臨時表等遍歷方法很常用。面對小數據量,這幾種遍歷方法均可行,但是面臨大數據量時,就需要擇優選擇,不同的遍歷方
【轉】【選型】【Dubbo】幾種RPC的選型比較
https://blog.csdn.net/liyanlei5858/article/details/77924407?utm_source=blogxgwz3 一、Dubbo通訊協議 第一、dubbo
scikit-learn幾種常用演算法的比較(code)
from sklearn import datasets import numpy as np iris =datasets.load_iris() X = iris.data[:,[2,3]] y = iris.target np.unique(y) #np.unique(y)返回儲
深度學習幾種主流啟用函式總結
啟用函式的定義 加拿大蒙特利爾大學的Bengio教授在 ICML 2016 的文章[1]中給出了啟用函式的定義:啟用函式是對映 h:R→R,且幾乎處處可導。 啟用函式的性質 非線性: 當啟用函式是線性的時候,一個兩層的神經網路就可以逼近基本上所有的函數了。但是,如果啟
幾種常見的資料庫連線的URL寫法
JDBC的URL=協議名+子協議名+資料來源名。 a .協議名總是“jdbc”。 b .子協議名由JDBC驅動程式的編寫者決定。 c .資料來源名也可能包含使用者與口令等資訊;這些資訊也可單獨提供。 幾種常見的資料庫連線 1 —oracle— 驅動
非線性優化-幾種優化方法的比較(1)
我們每個人都會在我們的生活或者工作中遇到各種各樣的最優化問題,比如每個企業和個人都要考慮的一個問題“在一定成本下,如何使利潤最大化”等。最優化方法是一種數學方法,它是研究在給定約束之下如何尋求某些因素(的量),以使某一(或某些)指標達到最優的一些學科的總稱。隨著學習的深入,博
幾種Boost演算法的比較(Discrete AdaBoost, Real AdaBoost, LogitBoost, Gentle Adaboost)
關於boost演算法 boost演算法是基於PAC學習理論(probably approximately correct)而建立的一套整合學習演算法(ensemble learning)。其根本思想在於通過多個簡單的弱分類器,構建出準確率很高的強分類器,PAC學習理論證
資料結構(一):幾種常見排序演算法比較
排序 0. 常見排序演算法效率比較 時間複雜度及穩定性比較 排序方法 平均方法 最優複雜度 最壞複雜度 輔助空間 穩定性 氣泡排序 O(
機器學習中的幾種距離度量方法比較
1. 歐氏距離(Euclidean Distance) /ju:'klidiən/ 歐式距離是最容易直觀理解的距離度量方法,我們小學,中學,高中所接觸的兩個空間中的距離一般都是指的是歐式距離。 二維平面上點a(x1,y1)與b(x2,y2)間的歐氏距離:
【Java】使用ScriptEngine動態執行程式碼(附Java幾種動態執行程式碼比較)
引言 在Java專案中,或多或少我們有動態執行程式碼的需求,比如: 系統中有一個規則驗證需求,但規則經常改變 程式碼熱更新,熱修復 筆者也在目前參與的一個專案中遇到了動態執行程式碼的需求:專案需要一個自動稽核模組,但是稽核規則根據相關書面檔案制定,如果寫死
幾種主流程式語言的優勢與不足
轉載地址:http://blog.csdn.net/dongfeng9ge/article/details/74634563 在初級程式設計師階段,每個人都不可避免遇到選擇程式語言和職業方向的難題。我挑選了幾個常見的程式語言,分析了優缺點和職業方向,以供想當程式設計師
幾種訊息佇列的比較
Kafka/Jafka Kafka是Apache下的一個子專案,是一個高效能跨語言分散式釋出/訂閱訊息佇列系統,而Jafka是在Kafka之上孵化而來的,即Kafka的一個升級版。具有以下特性:快速持久化,可以在O(1)的系統開銷下進行訊息持久化;高吞吐,在一臺普通的伺服器上既可以達到10W/s的吞吐速
java集合遍歷的幾種方式總結及比較
理 訂閱 隨筆- 41 文章- 0 評論- 29 集合類的通用遍歷方式, 用迭代器迭代: Iterator it = list.iterator(); while(it.hasNext()) { Object obj = it.next(); }
幾種分散式訊息系統比較(old)
0 引言 隨著網際網路行業的發展和IT技術在行業內的廣泛應用,許多網際網路企業的伺服器每天產生海量的日誌。如天翼閱讀平臺每天產生的PV日誌有上億條;淘寶網每天的使用者行為日誌達數TB大小。如何高效地收