最速KVS研究会:Google Level DB対Kyoto Cabinet
Google LeveDBは,前回までにインストールしてあったリビジョン36を使うことにします.
(svn updateするとなぜかエラーになった)
> wget http://fallabs.com/kyotocabinet/pkg/kyotocabinet-1.2.65.tar.gz > tar xvf kyotocabinet-1.2.65.tar.gz > cd kyotocabinet-1.2.65 > ./configure --enable-lzo > make (中略) g++ -march=native -g -O2 -Wall -fPIC -fsigned-char -g0 -O2 -o kcutiltest -L. -L/usr/local/lib -L/usr/local/lib -lkyotocabinet -llzo2 -lz -lstdc++ -lrt -lpthread -lm -lc /usr/lib/crt1.o(.text+0xa3): In function `_start1': : undefined reference to `main' *** Error code 1 Stop in /home/hoge/kyotocabinet-1.2.65.
あれ?ソースファイルもオブジェクトファイルも指定されていない...
$(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyotocabinet $(CMDLIBS)
↑この辺か...おかしいな,マニュアルには
.TARGET The name of the target; also known as ‘@’.
The shorter forms ‘@’, ‘!’, ‘<’, ‘%’, ‘?’, ‘>’, and ‘*’ are permitted for
backward compatibility and are not recommended.
推奨されていないけど互換性のために$<も使えるって書いているんですけどねぇ.
all: TestMake echo $<
こんなファイルをファイル名TestMakeとして作って試してみる.
> make -f TestMake echo > gmake -f TestMake echo TestMake TestMake
やっぱ$<が使えないや...しゃーないので,gmakeで.
> gmake g++ -march=native -g -O2 -Wall -fPIC -fsigned-char -g0 -O2 -o kcutiltest kcutiltest.o -L. -L/usr/local/lib -L/usr/local/lib -lkyotocabinet -llzo2 -lz -lstdc++ -lrt -lpthread -lm -lc (中略) #================================================================ # Ready to install. #================================================================ > su # make install (中略) #================================================================ # Thanks for using Kyoto Cabinet. #================================================================
それでは,LevelDB対Kyoto Cabinetを!
まずはKey-ValueのValueが10バイトの短い例を.
Valueがセッションのハッシュ値とか,本当にキャッシュとして使う場合.
LevelDBが速いようです.
もっとも,Kyoto Cabinetの方が圧倒的に機能豊富で現時点で使えているのは事実です.
KCのMapReduce機能は速くて気に入っています.
次にValueの長さが100バイトの例を.
Kyoto Cabinetは書き込みがシングルスレッド,マルチスレッドと試し,LevelDBは書き込みはシングルスレッドのみ(読み込みは,全てのケースでマルチスレッド)ですが,LevelDBが圧勝でした.
ところが,Valueの長さが1000バイトになると,Kyoto Cabinetの方が早くなりました.
ここからも,LevelDBがドメイン特化なことが分かります.
Kyoto Cabinetのベンチマークプログラムはこのような感じで,引数でDBの型も変えられるようになっています.ハッシュとかツリーとかディスクとかメモリとか.
#include "basic_header.h" #include <unistd.h> // for unlink() #include "kcpolydb.h" int main(int argc, char *argv[]) { int suc = 0, i; time_t start, set_end, get_end; int n = omp_get_max_threads(); kyotocabinet::PolyDB *db = new kyotocabinet::PolyDB(); if(argc!=2) { std::cout<<"KC db filename is required"<<std::endl; exit(1); } unlink(argv[1]); if (!db->open(argv[1], kyotocabinet::PolyDB::OWRITER | kyotocabinet::PolyDB::OCREATE)) { std::cerr << "open error: " << db->error().name() << std::endl; exit(1); } start = time(NULL); #pragma omp parallel for shared(suc,i, db) for(i=0;i<MAX_LOOP;++i) { Poco::MD5Engine con; string key, val; set_key_val(con, (int)(i/REP), key, val); if(!db->set(key, val)) { std::cout<<db->error().name()<<std::endl; }else { ++suc; } } set_end = time(NULL); #pragma omp parallel for shared(suc,i, db) for(i=0;i<MAX_LOOP;++i) { Poco::MD5Engine con; string key, val, expected_val; set_key_val(con, (int)(i/REP), key, expected_val); if(!db->get(key, &val) || val != expected_val) { cout<<"get: "<<val<<" KC error: "<<db->error().name()<<std::endl; }else { ++suc; } } // std::cout<<key<<val<<std::endl; #include "basic_footer.h" delete db; return(0); }
実行はこんな感じで.
> setenv OMP_NUM_THREADS 1 ; rm -fR /var/tmp/testdb.kch ; env LD_LIBRARY_PATH=/usr/local/lib/gcc45/ time ./kc_bench /var/tmp/testdb.kch
そう,見ての通り,.kch(ファイルベースハッシュDB)を使っています.
他のDBについては,また追って検証結果を報告致します.