memcachedのように使えるBloomFilter

YAPCでmalaさんの話を聞いていて、memcachedのようにお手軽に使えるbloom filterがあるとひょっとすると便利かもしれない、とふと思ったのでAnyEventつかって、Bloom::Fasterのwrapperを書いてみました。

https://github.com/walf443/p5-bloomd-server

以下のようなプログラムを書いてサーバーを起動します

use strict;
use warnings;
use EV;
use AnyEvent;
use Bloomd::Server

my $cv = AnyEvent->condvar;
my $server = Bloomd::Server->new(
    capacity => 100_000_000,
    backupdir => '.',
    ulog => 'ulog',
);
$server->run
$cv->recv;

起動したらncで会話できます。

$ echo "check foo" | nc localhost 26006 
CHECK foo 0
END
$ echo "check foo barfoo" | nc localhost 26006
CHECK foo 0
CHECK barfoo 0
END
$ echo "set foo" | nc localhost 26006 
OK
$ echo "check foo barfoo" | nc localhost 26006                                                                                                                 CHECK foo 1
CHECK barfoo 0
END

statsでサーバーの統計情報を知ることができます。

$ echo "stats" | nc localhost 26006
STAT capacity 100000000
STAT cmd_check 6
STAT cmd_set 1
STAT error_rate 0.001
STAT pid 87719
STAT server_id 1
STAT server_time 132001511179202
STAT uptime 237
STAT key_count 2970
STAT vector_size 1155555563
END

backupコマンドを実行すると、backupdirで指定したディレクトリに、snapshot + timestampというファイル名でbackupを取ることができます。

snapshot.132001522548775

backupするコマンドがXSレベルでファイルの読みかきをしているので、AnyEventをブロックしてしまうという問題は、redisをパクって、forkして子プロセスでバックアップファイルを作ることで解決しました。

from_snapshotでファイル名を指定すると、バックアップを使って、起動することができます。

また、レプリケーションをすることができます。

欠点としては、あまり早くないので、基本的には他にある既存のKVSを使った方がよいケースが多いでしょう。ただ、データをどれだけsetしても使用メモリ等は増えていかないので、そういう面で運用しやすさはあるのかなーと思っています。

今自分が使えそうかなーと思っているユースケースとしては、色々なユニークユーザーの件数の集計処理をリアルタイムで実現するのに使えるかもな、という感じです。(ユニークユーザーのデータを保持しようとするとたくさんのデータを保存しないといけないが、具体的なユーザーはわからなくてよく、だいたいのユニークがわかればよい)