下面性能測(cè)試對(duì)比來自LevelDB官方,由 NoSQLFan 進(jìn)行翻譯整理。從結(jié)果上看,這不像某些田忌賽馬式的性能對(duì)比,總體來說還是比較客觀全面。通過多種場(chǎng)景下的不同性能測(cè)試結(jié)果的對(duì)比,我們也能對(duì)這三個(gè)數(shù)據(jù)庫(kù)分別擅長(zhǎng)和適用的場(chǎng)合有所了解。同時(shí)對(duì)其性能調(diào)優(yōu)的方法理解也有一定的幫助。
下面是對(duì)LevelDB、TreeDB、SQLite3 這幾個(gè)數(shù)據(jù)庫(kù)的性能對(duì)比測(cè)試,分別使用了LevelDB (revision 39) SQLite3 (version 3.7.6.3) 及 Kyoto Cabinet’s (version 1.2.67)這三個(gè)版本的數(shù)據(jù)庫(kù)。
測(cè)試機(jī)器配置:six-core Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, with 12288 KB of total L3 cache and 12 GB of DDR3 RAM at 1333 MHz
文件系統(tǒng):測(cè)試腳本分別跑在兩臺(tái)機(jī)器上,其文件系統(tǒng)一臺(tái)為ext3(磁盤為 SATA Hitachi HDS721050CLA362),一臺(tái)為ext4(配備磁盤 SATA Samsung HD502HJ)
性能測(cè)試源碼:
- LevelDB: db/db_bench.cc.
- SQLite: doc/bench/db_bench_sqlite3.cc.
- Kyoto TreeDB: doc/bench/db_bench_tree_db.cc.
基本測(cè)試
基本測(cè)試的條件如下:
- 每個(gè)數(shù)據(jù)庫(kù)使用4GB內(nèi)存
- 數(shù)據(jù)庫(kù)都處于異步寫模式(LevelDB’s sync option, TreeDB’s OAUTOSYNC option, SQLite3’s synchronous options 都關(guān)閉),也就是說寫操作不用等數(shù)據(jù)真正寫到磁盤上才返回。
- Key 的長(zhǎng)度為16字節(jié)
- Value 的長(zhǎng)度為100字節(jié) (這個(gè)長(zhǎng)度才能讓數(shù)據(jù)庫(kù)的壓縮算法能夠起作用,將數(shù)據(jù)壓縮至50%大小左右)
- 順序讀寫時(shí)Key值遞增變化
- 隨機(jī)讀時(shí)生成隨機(jī)的Key值
測(cè)試結(jié)果:
結(jié)果顯示,在順序讀寫和隨機(jī)寫上,LevelDB 在性能上都遙遙領(lǐng)先,在隨機(jī)讀上面 Kyoto Cabinet 引擎稍快一些。
在幾種不同策略下進(jìn)行寫操作測(cè)試
A. Values 為長(zhǎng)數(shù)據(jù)(數(shù)據(jù)長(zhǎng)度為100,000字節(jié))
LevelDB在Value較長(zhǎng)時(shí)性能比較低,這是由于LevelDB對(duì)每一次寫操作都會(huì)至少進(jìn)行兩次寫動(dòng)作,一次是寫數(shù)據(jù)文件,另一次是寫日志文件。這里慢的主要原因是LevelDB在進(jìn)行這些操作時(shí)對(duì)值進(jìn)行了過多的Copy。
B. 批量寫操作
一次寫操作寫1000條100字節(jié)的數(shù)據(jù),由于TreeDB不支持批量寫入,故未對(duì)其進(jìn)行對(duì)比測(cè)試
上面結(jié)果是由于LevelDB數(shù)據(jù)的組織方式,導(dǎo)致順序?qū)懞碗S機(jī)寫在性能上都變化不大。
C. 同步進(jìn)行寫操作
- 對(duì) LevelDB, 設(shè)置 WriteOptions.sync = true.
- 對(duì) TreeDB, 將 TreeDB’s OAUTOSYNC 選項(xiàng)開啟.
- 對(duì) SQLite3, 設(shè)置 “PRAGMA synchronous = FULL”.
如果你看一下ext4文件系統(tǒng)下的測(cè)試數(shù)據(jù),你會(huì)發(fā)現(xiàn)ext3和ext4在表現(xiàn)上非常不同。
D. 無壓縮的寫操作
LevelDB 和 TreeDB 都支持相應(yīng)的數(shù)據(jù)壓縮算法(LevelDB 使用的是 Snappy , TreeDB 使用的是 LZO),由于SQLite不支持壓縮,所以這里的測(cè)試數(shù)據(jù)只是從上面的基本測(cè)試結(jié)果copy過來的。
LevelDB開啟壓縮比不開啟壓縮效率更高,而TreeDB則相反,這可能是由于TreeDB采用的壓縮算法(LZO)與LevelDB采用的壓縮算法(Snappy)相比計(jì)算代價(jià)更高。
E. 使用更大內(nèi)存
將每個(gè)獨(dú)立庫(kù)的內(nèi)存增大到128MB,對(duì)LevelDB來說,其中120MB用來做 write buffer,另外8MB用來做 cache(原來是2MB的 write buffer 和2MB的cache),對(duì)SQLite來說,我們不改變其page size,還是保持為1kb,但是我們?cè)龃笃鋚age數(shù)量從4k增加到128k,對(duì)TreeDB來說,我們同樣不改變其page大小,也只是增大其cache,從4MB增大到128MB。
SQLite 在采用了大內(nèi)存后性能變化并不大,而 LevelDB 和 TreeDB 的隨機(jī)寫性能卻有顯著提高。LevelDB 在增大內(nèi)存后性能提升的原因是其write buffer 更大,從而減少了創(chuàng)建的sorted file的次數(shù)。減少了磁盤IO。而 TreeDB 的性能提升原因是由于其數(shù)據(jù)庫(kù)的更大部分被映射到內(nèi)存中了。
在幾種不同策略下進(jìn)行讀操作測(cè)試
A. 大的Cache空間
我們分配128MB給每個(gè)數(shù)據(jù)庫(kù),對(duì)LevelDB來說,我們分配8MB給 write buffer,120MB給cache,對(duì)另外兩個(gè)數(shù)據(jù)庫(kù),由于它們不支持區(qū)分 write buffer 和cache,所以統(tǒng)一將 cache size設(shè)置成128MB。
從結(jié)果可以看到,增大Cache在數(shù)據(jù)庫(kù)讀性能上都有所提升,其中最為顯著的是TreeDB,其隨機(jī)讀性能大幅提升。主要是由于有足夠的內(nèi)存使得其所有讀操作都幾乎是在內(nèi)存中進(jìn)行。
B. 無壓縮的讀操作
下面結(jié)果是我們對(duì)預(yù)先無壓縮狀態(tài)寫入的100萬條key為16字節(jié)、value為100字節(jié)的數(shù)據(jù)后進(jìn)行的讀性能測(cè)試。同樣的 SQLite 由于不支持壓縮,所以下面數(shù)據(jù)是直接從其基本測(cè)試上copy過來的。
結(jié)果可以看到,取消壓縮對(duì)讀取性能提升不是特別大,當(dāng)然,如果你的數(shù)據(jù)都在內(nèi)存中的話,執(zhí)行解壓操作也不會(huì)對(duì)性能造成太大影響。