おそらくはそれさえも平凡な日々

PerlとRedis

この記事は Perl5 Advent Calendar 2015 の7日目の記事です。昨日は、 @karupanerura さんの XSことはじめ でした。

今回は、RedisをPerlで扱う上での便利CPANモジュールを紹介します。大体 @shogo82148 無双になります。

Redis::Fast

RedisクライアントはRedis::Fast一択です。Redis.pmが公式推奨のモジュールですが、これはPure Perl実装なのでパフォーマンスがそれほど良くありません。

Redis::FastはRedis.pm互換のインターフェースを持ったXSモジュールであり、内部的にはRedis公式のCクライアントであるhiredisのバインディングになっているので、安定していて使いやすいといえるでしょう。

my $redis = Redis::Fast->new;
$redis->incr('blah');

Cache::Redis

Redisの用途としてキャッシュがまず考えられますが、キャッシュ用のモジュールとして便利なのがCache::Redisです。別にRedisをそのまま使ってもいいのですが、以下の様な点でCache::Redisは便利です。

  • Perlの世界で慣例的なCache::Cacheインターフェースに即している
    • セッションのバックエンドなどでの差し替えが容易
  • オブジェクトのシリアライズ/デシリアライズに対応
    • 用量・用法を守って使用しましょう

使い方は以下のとおりです。

my $redis = Redis::Fast->new; # you can use Redis.pm too.
my $cache = Cache::Redis->new(redis => $redis);
$cache->set(blah => {hoge => 1});
say $cache->get('blah')->{hoge}; # 1

ちなみに、単純にキャッシュ用途のみを考えると、 Cache::Memcached::Fast の方が高速になることが多いので、用途に応じて使い分けをするのが良いと思います。(今年のISUCON5の予選ではRedisを使い、決勝ではmemcachedを利用しました)

Redis::LeaderBoard

Redisのsorted setは強力でランキングを作るのに適していることは知られているところです。ただ、コレもよく知られているところですが、sorted setには同点問題というものがあります。

いくつかコマンドを組み合わせることで、同点をケアした順位を出すことは可能ですが、その辺りのコマンド発行を毎回手でやるのは大変です。それをラップしてRedisをランキングストレージとして扱うためのモジュールがRedis::LeaderBoard-です。

my $redis = Redis::Fast->new;
my $lb = Redis::LeaderBoard->new(
    redis => $redis,
    key   => 'leader_board:1',
    order => 'asc', # asc/desc, desc as default
    limit => 100,   # optional
);
$lb->set_score(one => 100);
$lb->set_score(two =>  50);
my ($rank, $score) = $lb->get_rank_with_score('one'); #=> (1, 100)

昇順、降順でも同じインターフェースで扱えるので便利です。また、バージョン1.1以降では limit オプションをサポートし、設定した場合sorted setの要素数を自動的に切り詰めてくれるようになりました。

Redis::Namespace

Redisはプログラム言語で扱うような各種データ構造をそのまま突っ込むことができるので非常に強力ですが、それは、グローバル変数以上に強力なグローバル変数であるとも言えるので、思わぬところに保存して、キーがバッティングしたりしないように適切に管理したいところです。

それを解決するためのモジュールが Redis::Namespace ですRedis::Namespaceを使えば、プレフィクスにコロン区切りのネームスペースを自動的に付けてくれます。

my $redis = Redis::Fast->new;
my $ns = Redis::Namespace->new(redis => $redis, namespace => 'fugu');
$ns->set('foo', 'bar');    # will call $redis->set('fugu:foo', 'bar');
my $foo = $ns->get('foo'); # will call $redis->get('fugu:foo');

Redis::NamespaceはRedis.pm互換のインターフェースを持っているところが面白いところで、$redis のオブジェクトを渡すようなところを、Redis::Namespaceのオブジェクトに差し替えることで安全にRedisを利用することが可能です。例えば、以下のようにRedis::LeaderBoardと組み合わせることができます。

my $ns = Redis::Namespace->new(redis => Redis::Fast->new, namespace => 'ranking');
my $lb = Redis::LeaderBoard->new(
    redis => $ns,
    key   => 'leader_board:1',
);

同じようなコンセプトのモジュールで同じ作者の Redis::Keys というものもあります。こちらも便利そうなので、利用を検討してみても良いかも知れません。

まとめ

PerlでRedisを活用するための各種CPANモジュールを紹介しました。

明日は @kfly8 さんです。お楽しみに!

created at
last modified at

2015-12-07T22:09:31+0900

comments powered by Disqus