okuyamaのSerializeMapを検証してみた

昨日@kumagi さんと@muga_nishizawa さんとtwitter上でやり取り(http://togetter.com/li/149955)をした時に話題に出した
次のokuyamaに入れようと思っている機能の一つのSerializeMapですが、
あの時、性能の話題になったのでまだ正式にはリリース前なんですが
性能を簡単に測定してみました。
実装したタイミングで簡単には試していたのですが、自分の備忘録代わりに再テストの記録。


そもそもこのSerializeMapの仕組みですが、このMapは内部で1つだけMapオブジェクトを
持っていてこのMapはあらかじめ決められた要素数しかKeyとValueのセットを持たないようになっています。
そして全ての要素はIntegerオブジェクトをKeyとして、ValueシリアライズされたMapのバイナリ
配列をもちます。このバイナリ配列化されたMapを逐次、デシリアライズてそこに値をつめて、
またシリアライズして大本のMapに登録し直します。決められた要素のどこのMapに入るかは
登録時のKey値のHash値を使って素数で割ってその余りの場所に格納しています。この大本Mapの
素数は引数で渡して調整出来るようになっています。
狙いはメモリ中に存在しているMapオブジェクトの要素数を増やさないことです。
要素内のシリアライズされたバイトデータは増えますが、要素数そのものが増えることに
よるオブジェクトの構成要素が占めるメモリ中の容量よりもマシではないかと思い実装しました。


取り合えず測定の視点は、単純に秒間に実行できる性能と、メモリに対してどれぐらい保持できるかです。
参考としてConcurrentHashMapと比べてみました。


以下はSerializeMapのソース
http://sourceforge.jp/projects/okuyama/svn/view/trunk/src/okuyama/imdst/util/serializemap/SerializeMap.java?view=markup&revision=671&root=okuyama


以下はテストに利用したソース
http://sourceforge.jp/projects/okuyama/svn/view/trunk/test/SerializeMapTest.java?view=markup&revision=675&root=okuyama




テストは簡単で、テストスクリプト内で値をSetするスレッドを複数起こして、
それぞれがユニークな値をSetするというもの
このSetを一定時間繰り返してその間にSet出来た回数を実行秒数で割って秒間処理数を、
保存できる最大はOutOfMemoryが出るまで実行してメモリ当たりの最大数を見てみました。
実行回数確認時は各スレッド単位でユニークな値を200万種類の中からランダムに登録し続けたので、
新規、更新入り乱れてると思います。


実行PCのスペックは以下
マシン:ドスパラデスクトップPC
CPU:Core i5 3.2GhHz 物理2コア、仮想4コア
メモリ:4GB
OS:CentOS 5.4 64bit
JAVA:Sun Java1.6.0_25 64bit


JVMオプションは以下にしました。

  • XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseParNewGC

メモリ割当は秒間当たりの処理数を調べる時は-Xmx2048m -Xms2048mで
最大数を調べるときは時間短縮のため、-Xmx512m -Xms512mで試しました。




ではまず1秒当たりのSetの数です。
同時にSetを実行するスレッド数は30です。
*ConcurrentHashMap
775030 QPS


*SerializeMap
62166 QPS


ConcurrentHashMap速い!!
77万とかいくんですね。
対して、SerializeMapは6万なので、12分の1位でしょうか。






ではつぎに、限界格納数
同時にSetを実行するスレッド数は8です。
*ConcurrentHashMap
197万6128件でOutOfMemory


*SerializeMap
2100万以上1時間半ぐらい動いた時点で止めました。


だいたい、同じメモリ量で、11倍以上格納出来ています。
格納のスピードはというと、ConcurrentHashMapは止まるまで
秒間当たり、ほぼ同じスピードでSetし続けたのに対して、
SerializeMapは以下のようになりました。
以下のログは3秒間隔でその時点のMapのsizeを出しています。


開始直後
1108159
1263967
1413241
1563692
1729365
大体、3秒で15万から16万件のペースでsizeが増えているので、
秒間当たり、5万Setできているのが分かります。


そして、1000万を超えた当たりでは、
10046581
10142857
10227589
10321581
10405751
大体、3秒で8万件から10万件程度増えているので、秒当たり、3万Setぐらでしょうか。


そして、2000万を超えたあたりでは、
19999741
20002336
20004813
20007616
20009919
大体、3秒で2000件から3000件程度増えているので、秒当たり、900Setぐらでしょうか。




内部でシリアライズ、デシリアラズを常に行い、さらに圧縮処理を行っているので、データが多くなれば
それだけ遅くなっているようです。
スピードは秒間1万Set程度でいいから大量の値を持ちたいよって時に、使えるかな。
okuyamaは内部でこれを使っているので、周りにネットワーク処理とか同期処理とか色々入るので、
この生の性能は出ませんが、データファイルの位置記録用には結構重宝しそうです。


次はGetも検証してみたいと思います。