そろそろネタが尽きてきたが頑張る。RiakをDocument DBっぽく使いたいときはデータをJSONで半構造化してからしまっておくとMapReduceとの相性がよいのだが、いかんせんJSONは効率が悪い。そりゃあJavaScriptからだと使いやすいが、データベースには優しくない。そこで有名なJSONっぽく使えるMessagePackというシリアライザを使ってデータを入れてみることにする。
ベンチマークに使うデータ
2013年2月6日時点での日本語Wikipediaダンプを使うことにする。ここにある
2013-02-16 20:47:28 done All pages, current versions only.
2013-02-16 20:47:27: jawiki (ID 8367) 2323070 pages (346.1|11655725.2/sec all|curr), 2323070 revs (346.1|351.2/sec all|curr), 93.1%|93.1% prefetched (all|curr), ETA 2013-02-18 08:04:06 [max 46273717]
jawiki-20130216-pages-meta-current.xml.bz2 2.0 GB
というリンクからとってきたXMLファイルを使う。bz2だからこのサイズになるが、解凍すると10GBほどある。Python標準のDOMを使うと、これのロードだけで仮想メモリ含めて50GBほど使ったところで実験は中止だったので…かといってSAXだとプログラミングが面倒だし、といったところでlxmlという神のようなライブラリがあったのでこれを使うことにする。iterparse()はみんな使うべきだ。特にWikipediaのダンプデータで苦しんだ人。
中をみるとテキストだけじゃなくて、いろいろなメタデータが入っているので、本文の小さな記事が多ければmsgpackの効果は大きそうだ。そうじゃなきゃJSONとはそう差がつかないだろう。と予め予想していた。基本的には、このXMLを素直にPythonのdictとかlistとかのデータ構造に変換しただけ。
それにしても12月のはずなのに未来のデータが使えるなんて不思議だ。
Riakの起動
1.3ブランチをソースからとってきてビルドした。2iを使うアプリを想定しているのでバックエンドはeleveldb。特に複数台構成はしないがN=3。ディスクの容量はまあ数百GBあったので十分だろう。それにしても12月のはずなのに未来のソースコードが使えるなんて不思議だ。
JSONで格納する
ソースコードはimporter2.pyだ。ややこしいことはいわずに入れてみる。
$ time python importer2.py jawiki-20130216-pages-meta-current.xml.bz2; date (snip ... ずっと流れる) real 352m44.883s user 56m31.120s sys 5m18.252s Sun Feb 24 04:23:11 JST 2013 $
6時間ほどかけて全部入った。Riakのデータディレクトリをみると
$ du data --max-depth=1 12 data/ring 268 data/kv_vnode 28018876 data/leveldb 697128 data/anti_entropy 28716288 data
28GBほど使っている。また、この間のRiak本体のCPU usageは120〜140%, iotopをみていると4〜8MB/sのIOが割と安定して発生していた。VIRTは15g, RESは8gくらい?だったかな記憶が…。
msgpackで格納する
こんどはimporter3.pyを使ってみる。
$ time python importer3.py jawiki-20130216-pages-meta-current.xml.bz2; date (snip ... 同様に沢山流れる) real 231m50.523s user 78m50.612s sys 8m8.491s Sun Feb 24 15:57:41 JST 2013 $
4時間ほどかけて入る。1.5倍速いですね!!!
$ du data --max-depth=1 8 data/ring 268 data/kv_vnode 21649456 data/leveldb 637196 data/anti_entropy 22286932 data
これで使った容量は21.6GBほど。22%ほど改善できている!さすがmsgpack!!! この間のRiak本体のCPU usageは100〜120%, iotopをみていると2〜4MB/sのIOがそこそこ発生していた。VIRTは9000mほど使っていて、Riakに対する負荷も軽いことがわかる。
結果の比較
JSON | msgpack | |
put時間 | 6時間 | 4時間 |
ディスク消費 | 28.0GB | 21.6GB |
可読性 | ◯ | △ |
可読性も悪くない。http getしてみるとわかるが、圧縮や暗号化をしているわけではないのでふつうに文字列のところは読める。これが僕は案外好きだ。JSONだとMapReduceするときに扱いやすいのだが、msgpackでも同様にJS実装があるので、それを使う解説はまた後日。
容量は22%削減ということだが、Riakは内部的に3つのコピーを持っているので、実際のデータサイズの差は22/3で7%程度だということがわかる。PUT時間が1.5倍も異なるのは、サイズの違いに由来するRiakの負荷と、Python側でエンコードも行なっていてその処理時間の差もあると思われる。