2010年01月18日

スケート頑張りすぎて足首が痛いYappoですみなさまウインタースポーチュしてますか?

本日kumofsが公開されたので、折角なので Data::Model から kumofs を実際にどうつかっているかを紹介しようかとおもいます。

kumofs については 分散Key-Valueストア「kumofs」を公開しました! - 古橋貞之の日記 を Data::Model::Driver::Memcached については dann さんによる Data::Model::Driver::Memcachedで超効率データ保存 - JPerl Advent Calendar 2009 を別途参照すると良いでしょう。

スキーマ定義

では実際に kumofs をつかった場合のスキーマ定義を下記に貼ります。
ちなみに、それらしいような定義をしてますが全部フィクションです。本当に。

解説 その1

Data::Model::Driver::Memcached のインスタンスを作る所で、 Cache::Memcached::Fast のインスタンスを指定する所で、3つのオプションを渡しています。

一つ目が、 serializer => 'Default', で、 Cache::Memcached 標準の直列化手段をつかわずに Data::Model::Driver::Memcached 標準の直列化手段を利用します。
即ち MessagePack を使った直列化を施します。 Data::Model で必要な MessagePack のコードは Pure Perl で内部的に実装されているのですが、実用的にするには Data::MessagePack をインストールしておくと、そっちを使って高速に直列化してくれます。

二つ目は、strip_keys => 1, です。
通常の方法だと、 primary key も KVS の Value として直列化してストレージに格納しようとするのですが、 KVS だったら既に Key のほうに値が入っているべきで、この重複が無駄なので削除して直列化します。
例えば、上記のコードを使った場合に以下のようなデータ構造だった場合に

{
    file_id    => 'dankogai',
    media_type  => 1,
    client_type => 5,
    is_broken   => undef,
},
file_id の項目を delete して、下記のような構造にしてから直列化します。
{
    media_type  => 1,
    client_type => 5,
    is_broken   => undef,
},

三つ目としては ignore_undef_value です。
これは何をする物かと言うと、カラムの値が undef だった場合は、その項目を DELETE してから直列化します。
そして lookup などで kumofs から Data::Model の Row オブジェクトに戻す時点で、直列化されてるデータにカラムのデータが無ければ value が undef だったと解釈をして復元するのです。
今回の例では、画像が壊れてた時だけ kumofs のストレージサイズが増加します。
上ので書いたデータ例に適用すると下記の用に is_broken が削除されて kumofs に格納されます。

{
    media_type  => 1,
    client_type => 5,
},

ユースケースとしては、稀にフラグを立てる必要があるんだけど、フラグ立って無いレコードに対してもディスク容量を消費するのが嫌だ!という時に使えます。
SQL だと、別途 file_broken 的なテーブルを作って JOIN すれば済む話でしょう。
あいにく kumofs では JOIN 出来ないので、このような時は別の Key-value にデータを突っ込まないといけません。
そうすると GET する時のクエリの数が倍になったりするのでトレードオフしてどっちにするか選ばなきゃいけなくなるんですが、 ignore_undef_value を使っとけば、必要な時に必要なだけストレージを使いつつ GET する時のクエリ数も増えないので良い感じになるんです。

細かいこと言うと SQL で別テーブル使って JOIN するよりかは空間効率やらなんやらは良いと思うすけど。特に比較検証してないんでこれ以上はやめとくす。

解説 その2

今度は model 定義部分をみてみましょう。ポイントは二つあります。

一つ目は schema_options model_name_realname => 'f_m'; です。
これは、 memcached protocol の key の所に入れる model namespace を短縮するのに使います。
例えば key=file_id が 'dankogai' だとして、 schema_options model_name_realname が指定されてない場合は、このコード例では

kumofsfile_meta:dankogai
という key で kumofs に SET します。
そして、今回の例の schema_options model_name_realname を使うと
kumofsf_m:dankogai
と短縮された key になります。

二つ目は schema_options column_name_rename の所です。
これは直列化する直前で Key を任意の値に変換してから直列化をかけます。
Data::Model 標準のシリアライザの MessagePack では、数値をとても効率よく直列化してくれるので、 media_type だとかいう長ったらしい key name を 2 とか言う数値に変換してしまいます。
2 とかという小さい値だと直列化後も1バイトしか容量食わなくて嬉しいんです!

実際、上のほうで書いてるデータ例だと以下の用になります。

{
    2 => 1,
    3 => 5,
},
とんでもなく圧縮出来ている事がお分かり頂けますか。

MessagePack の specをみても解るとおり、15要素以下の HASH に1バイト、 7bit 以下の unsigned int では1バイトの容量しかかからないので、上記の圧縮後の value は5バイトという驚異的なサイズとなって kumofs の value に格納されます。

まとめ

今日は kumofs 公開したということで、 Data::Model からだったらどう使えるか、どう使うかという視点で書いてみました。
Data::Model 側で用意してるオプションを使い切る事により、プログラムコードは書き易く、かつ空間効率を驚異的に高めて利用出来る事が解ったかと思います。
もちろん Data::Model::Driver::Mecached は kumofs 専用という訳でなく Tokyo Tyrant やらなんやらでも利用できますので、機会があればお試しください。

まぁ、もちろんこんなレイヤ介さずに直接使えばいいって話も出てきそうですがね。

あわせて読みたい:YappoLogs: KVSでORマッパーを使うという事 Posted by Yappo at 2010年01月18日 12:31 | TrackBack | Perl

Comments
Post a comment









Remember personal info?






コメントを投稿する前に↓の場所にnospamと入力してください。