2009-07-19
ベンチマークその2
Kai, Tokyo Cabinet |
前回に引き続いて、Kai+Tokyo Cabinetのテストです。
今回は、Kaiのインスタンスを3つ立ち上げてのテストです。が、ノートパソコン1台で3つのインスタンスを立ち上げてるので、Kaiの想定している分散環境とは全く異なると思われます。
(n,r,w)=(3,2,2)のとき
| データストア | 平均set時間[秒](失敗回数) | 平均get時間[秒](失敗回数) |
|---|---|---|
| ets | 0.00230(0) | 0.00094 (0) |
| dets(sync) | 0.35791(36) | 0.00470(3) |
| tcerl(sync) | 0.06441(1) | 0.00191(0) |
| dets(async) | 0.00280(1) | 0.00137(2) |
| tcerl(async) | 0.00241(0) | 0.00110(0) |
データストアによっては、タイムアウトのエラーが出てしまいました。エラーによってKaiの動作が完全に停止することはありませんでしたがやや気になります。上記の値は、データストアが空の状態から10000個のエントリを足すもので、この後に継続してエントリを足していくと、ets, tcerl(async)ともに3万〜4万エントリを足すあたりでタイムアウトエラーが出始めます。libmemcachedのデフォルトタイムアウトは何秒なんだろう?
推測してもしょうがないので、あとでプロファイラでいろいろ調べてみることにします。
(n,r,w)=(1,1,1)のとき
対障害性とか一貫性とかを考えずに、単に分散Key-Valueストアとして動かした場合です。
| データストア | 平均set時間[秒](失敗回数) | 平均get時間[秒](失敗回数) |
|---|---|---|
| ets | 0.00170(0) | 0.00052 (0) |
| dets(sync) | 0.13900(8) | 0.00171(2) |
| tcerl(sync) | 0.01851(0) | 0.00099(0) |
| dets(async) | 0.00245(0) | 0.00059(0) |
| tcerl(async) | 0.00193(0) | 0.00062(0) |
dets(sync)では、こちらでもエラーが出てます。dets(async)は2万〜3万エントリでエラーが出始めました。ほかは5万エントリ入れてもエラー無しです。ただ、どのデータストアでもじわじわと性能が悪くなっていたので、ある程度エントリを加えていけばエラーが出てしまうのではと想定されます。
ここまで見た限り、tcerlでお手軽にTokyo Cabinetを接続するのはそれなりに効果があるように思えます。tcerlでは、無駄にordered setになっているので、ハッシュ表を使ってsetタイプにしたらもっと高速化できるのではないでしょうか? でも、kai_store_xxx:do_list/2で、table内の特定のbucketの検索しているところを高速化しようとすると、テーブルデータベースタイプを使うほうがいいですかね?
2009-07-16
ベンチマーク
Kai, Tokyo Cabinet |
libmemcachedで快速キャッシュ生活 - mixi Engineers’ Blogのmemstorm*1を使ってシーケンシャルな読み書き性能を見てみました。
実験環境は
$ ./memstorm -s 127.0.0.1 -n 10000 -k 64 -l 10240 -b -t
として、64byteのキー、10240byteの値をもつエントリを10000回読み書きしています。
今回はKaiのサーバは1台、(n,r,w)=(1,1,1)で実験です。
ets版
Average Time [SET] : 0.00118s Average Time [GET] : 0.00030s
dets版
Average Time [SET] : 0.14143s Average Time [GET] : 0.00094s
書き込みが相当遅いですね。
tcerl版
Average Time [SET] : 0.02152s Average Time [GET] : 0.00071s
だいぶ性能があがってますね。Tokyo Cabinetの各種パラメータをいじれば、格納するデータセットに応じてチューンすることも可能でしょうし。
asyncにすると?
現在のkai_store_{dets/tcerl}では書き込みのあとにsyncをかけています。このsyncをとってしまえば、ディスクの書き込み待ちをなくせるので相当性能アップが期待できます。単に、メモリ容量以上の一時的なストレージが欲しい、という場合にはsyncをとってしまってもいいかもしれません。
dets(async)
Average Time [SET] : 0.00157s Average Time [GET] : 0.00034s
tcerl(async)
Average Time [SET] : 0.00134s Average Time [GET] : 0.00038s
100MByte程度のデータセットなので、すべてメモリ上のキャッシュに乗ってしまいetsと同等の性能になっていますね。
次はクラスタ構成でのテストとか、並列リクエストに対するテストとかが気になります。それに関してはまた後日。
2009-07-15
Kai + Tokyo Cabinet
Tokyo Cabinet, Kai |
分散KeyValueストアのKaiは、ストレージとしてetsかdetsが選べます。試しに、ストレージとしてTokyo Cabinetを使う方法を考えてみました。
今回は、ErlangからTokyo Cabinetを使うためのライブラリとしてtcerlを使ってみます。このライブラリでは、Tokyo CabinetのB+木データベースに対してets/detsとほぼ同様のインタフェースを提供しています。ですので、ストレージ部がets/detsになっているKaiにTokyo Cabinetをつなげるにはうってつけです。
Kaiがストレージ部分をきちんと切り分けているお陰で、変更部分は非常に解りやすくなっています。ほぼ、kai_store_dets.erlに"s/dets/tcdbdets/g"しただけ、といってもよいでしょう。
$ diff kai_store_dets.erl kai_store_tcerl.erl 13c13 < -module(kai_store_dets). --- > -module(kai_store_tcerl). 29c29,36 < Dir = kai_config:get(dets_dir), --- > TcLibdir = kai_config:get(tc_libdir), > case erl_ddll:load_driver (TcLibdir, libtcbdberl) of > ok -> ok; > { error, already_loaded } -> ok; > { error, permanent } -> ok > end, > TcOpts = kai_config:get(tc_opts), > Dir = kai_config:get(tc_dir), 34,36c41,43 < Name = list_to_atom(atom_to_list(?MODULE) ++ "_" ++ integer_to_list(I)), < File = Dir ++ "/" ++ integer_to_list(I), < case dets:open_file(Name, [{type, set}, {keypos, 2}, {file, File}]) of --- > % Name = list_to_atom(atom_to_list(?MODULE) ++ "_" ++ integer_to_list(I)), > File = Dir ++ "/" ++ integer_to_list(I) ++ ".tcb", > case tcbdbets:open_file([{type, ordered_set}, {keypos, 2}, {file, File} ] ++ TcOpts) of 48c55 < fun({_I, Table}) -> dets:close(Table) end, --- > fun({_I, Table}) -> tcbdbets:close(Table) end, 76c83 < ListOfData = dets:select(Table, [{Head, Cond, Body}]), --- > ListOfData = tcbdbets:select(Table, [{Head, Cond, Body}]), 81c88 < case dets:lookup(Table, Key) of --- > case tcbdbets:lookup(Table, Key) of 88c95 < case dets:lookup(Table, Data#data.key) of --- > case tcbdbets:lookup(Table, Data#data.key) of 98,99c105,106 < dets:insert(Table, Data), < dets:sync(Table), --- > tcbdbets:insert(Table, Data), > tcbdbets:sync(Table), 104c111 < case dets:lookup(Table, Key) of --- > case tcbdbets:lookup(Table, Key) of 106,107c113,114 < dets:delete(Table, Key), < dets:sync(Table), --- > tcbdbets:delete(Table, Key), > tcbdbets:sync(Table), 119,120c126,127 < bytes -> dets:info(T, file_size); < size -> dets:info(T, size) --- > bytes -> tcbdbets:info(T, file_size); > size -> tcbdbets:info(T, size);
そして、tc_libdirなどのオプションを読み込めるようにkai.erlのstart/2を書き換え、Makefileにkai_store_tcerl.erlを追加すれば完了です。
kai.configには、以下の記述を加えます。
[{kai, [
...
{store, tcerl}, % ストレージモジュールの指定
{tc_dir, "/tmp/kai"}, % ファイルの格納場所
{tc_libdir, "/usr/local/lib"}, % tcerlのlibtcbdberl.soがあるディレクトリ
{tc_opts, []}, % Tokyo Cabinetへの各種オプション
...
]}].
そして、今まで通りにkaiを起動すれば動いているはずです*1。ドライバはasynchronousに動くので、+Aオプションを加えた方がよいかもしれません。
$ erl -pa ebin -config kai
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]
Eshell V5.7.2 (abort with ^G)
1> application:start(kai).
2009-07-16 00:11:13.855866 [info] (<0.43.0>) ./kai_hash.erl:183: {update,
[{{{127,0,0,
1},
11011},
[{number_of_virtual_nodes,
128}]}],
[]}
ok
2>
動作確認してみます。
$ telnet 127.0.0.1 11211 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. set Test 0 0 10 ThisIsTest STORED get Test VALUE Test 0 10 ThisIsTest END stats STAT uptime 26 STAT time 1247672820 STAT version 0.4.0 STAT bytes 68288512 STAT curr_items 1 STAT curr_connections 1 STAT cmd_get 1 STAT cmd_set 1 STAT bytes_read 10 STAT bytes_write 10 STAT kai_node 127.0.0.1:11011 STAT kai_quorum 1,1,1 STAT kai_number_of_buckets 1024 STAT kai_number_of_virtual_nodes 128 STAT kai_store tcerl STAT kai_curr_nodes 127.0.0.1:11011 STAT kai_unreconciled_get STAT erlang_procs 85 STAT erlang_version 5.7.2 END quit Connection closed by foreign host. $
動いたからにはベンチマークでも、と思いましたが、それはまた後日。
*1:LD_LIBRARY_PATHを指定する必要があるかもしれません