Spread Toolkit + Perl で cagra みたいなのを実装してみた

分散ストレージシステム Cagra が面白そうだなあと思いつつ以下の図を見たら、

これ、Spread Toolkit でセッションレプリケーション - 酒日記 はてな支店 で書いた図に似ているなと。
要するに、client は localhost(でなくてもいいけど) の daemon と通信し、daemon 同士は udp multicast 等でメッセージ交換する、という形が一緒。
であれば、Spreat Toolkit を使えば似たようなのが実装できるんじゃないか、ということで作ってみた。
ソースは coderepos に置いてあります。http://svn.coderepos.org/share/lang/perl/Spread-DStorage/

Spread については日本語の情報がほとんど見つからないので、手前味噌ですが http://d.hatena.ne.jp/sfujiwara/searchdiary?word=Spread も参考までに。

Spread daemonlocalhost:4803 で通信できるのを前提として、サーバ (ストレージ担当) プロセスを以下のように起動。

use Spread::DStorage::Server;
my $server = Spread::DStorage::Server->new;
$server->run;

すると、クライアントから以下のように使えます。

use Spread::DStorage::Client;
my $client = Spread::DStorage::Client->new;
$client->set( foo => "bar" ); # key=foo に value=bar を設定
$value = $client->get('foo'); # key=foo の値を取り出し

サーバに複数のノードを使った場合には Consistent Hashing(みたいなの) を使って、ノードが増減してもキャッシュヒット率が悪化しないようにしてみました。レプリケーションはとりあえずなし。
ノードの増減は、サーバがそれぞれ自動で検知します。
# Spread 自体の増減は手動で設定しないとだめですが……

サーバはデフォルトではメモリ上にデータを保持するだけですが、tie hash を渡してやればそこ経由で書き込むので、例えば Tokyo Cabinet を使う場合は以下のような感じで永続化可能。

use TokyoCabinet;
my %storage;
tie %storage, "TokyoCabinet::HDB", "storage.hdb", TokyoCabinet::HDB::OWRITER | TokyoCabinet::HDB::OCREAT
    or die $!;
my $server = Spread::DStorage::Server->new({ storage => \%storage });
$server->run;

かなりいい加減な実装なので、

  • 巨大なデータは勘弁してくれとか(Perlの変数に入れられるぐらいで)
  • パフォーマンスはそんなに出ないかも (サーバ側も Perl だし)

とかありますが、サーバ側 90行、クライアント側 50行ぐらいで書けたのでとりあえず満足。