ひとりでやるRiak Advent Calendar 2012 day17 - msgpackでHappy Riak life

1909 Message side of packing house card.

そろそろネタが尽きてきたが頑張る。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側でエンコードも行なっていてその処理時間の差もあると思われる。