Hatena::ブログ(Diary)

とりあえず、一応、その方向で

2009-07-19

ベンチマークその2

| 21:51

前回に引き続いて、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

ベンチマーク

| 11:05

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と同等の性能になっていますね。

次はクラスタ構成でのテストとか、並列リクエストに対するテストとかが気になります。それに関してはまた後日。

*1:これをインストールするためにはlibmemcachedが必要、libmemcachedをインストールするためにはmemcachedが必要、memcachedインストールするためにはlibeventが必要。まさにYak shaving

2009-07-15

Kai + Tokyo Cabinet

| 00:54

分散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を指定する必要があるかもしれません