Redisの活用例
Redisの基本的な機能を見たところで、
セッションストアやキャッシュ
Redisはデータを一時的に保存するのに適しているので、
ただし、
ネストしたハッシュや配列のような複雑なデータをRedisに保存したい場合は、
my $redis = Redis::Fast->new;
my $cache = Cache::Redis->new(
redis => $redis
);
$cache->set('key' => {hoge => 1});
print $cache->get('key')->{hoge};
また、
リアルタイムランキング
ソート済みセット型は順位の計算を高速に行えるので、
ただし、
ランキングの目的によっては、
my $redis = Redis::Fast->new;
my $lb = Redis::LeaderBoard->new(
redis => $redis,
key => 'leader_board:1',
order => 'asc', # asc/desc
);
$lb->set_score(one => 100);
$lb->set_score(two => 50);
my ($rank, $score) =
$lb->get_rank_with_score('one');
場合によっては、
排他制御
cronを使ってジョブを実行する場合などに、setlock
コマンドがよく使われますが、
次のようなコマンドで、program
を排他的に実行できます。
$ redis-setlock KEY program
ライブラリとして利用することもできます。
my $redis = Redis::Fast->new;
my $g = Redis::Setlock->lock_guard($redis,'key');
if ($g) {
# ロック獲得成功
}
else {
# ロック獲得失敗
}
Redisのテスト
実際のサービスでRedisを活用するのであれば、
開発用にRedisサーバを準備してもよいのですが、
use Redis::Fast;
use Test::RedisServer;
use Test::More;
# テスト用のRedisサーバを立ち上げる
my $redis_server = Test::RedisServer->new;
# テスト用のRedisサーバに接続する
my $redis = Redis::Fast->new(
$redis_server->connect_info
);
# Redisを使ったテスト
is $redis->ping, 'PONG', 'ping pong ok';
done_testing;
Redisのキーを便利に使うユーティリティ
Redisは便利なKVSですが、
Redis::Namespace──キー名への接頭辞付与を自動化する
Redisではキー名に接頭辞を付けて、
接頭辞を付ける作業を毎回手動で行っていると、
Redis::NamespaceはRedis::Fastとインタフェースの互換性があるので、
my $redis = Redis::Fast->new;
my $ns = Redis::Namespace->new(
redis => $redis,
namespace => 'ns',
);
# $redis->set('ns:key', 'value');
$ns->set('key' => 'value');
# $redis->get('ns:key');
print $ns->get('key');
Redis::Namespaceのインタフェース互換性を応用すると、
Redis::Key──Redisのキーのラッパモジュール
「user:ユーザーID」
Redis::KeyはRedisのキーのラッパモジュールです。プレースホルダを使ってsprintf
を用いたり、
# キー名のルールを決める
my $redis = Redis->new;
my $user = Redis::Key->new(
redis => $redis,
key => 'user:{id}',
need_bind => 1,
);
# キー名にIDを埋め込む
my $key = $user->bind(id => 123);
# $redis->set('user:123', 'value');
$key->set('value');
# $redis->get('user:123');
$key->get;
Redisを利用するうえでの注意点
Redisは強力ですが、
計算量
最近のコンピュータはマルチコアのものが主流ですが、
たとえば、LPUSH
コマンドやLPOP
コマンドの計算量はO(1)です。これは、LINDEX
コマンドはインデックス番号を指定してリスト型の要素を取得するコマンドですが、
両者の違いを見るためのベンチマークプログラムを書いてみました。
use strict;
use warnings;
use Parallel::Benchmark;
use Test::RedisServer;
use Redis::Fast;
use Log::Minimal;
my $redis_server = Test::RedisServer->new;
my $redis = Redis::Fast->new(
$redis_server->connect_info
);
my @n = (
1,
10,
100,
1_000,
10_000,
100_000,
1_000_000,
);
sub bench_lindex {
my $count = shift;
my $bm = Parallel::Benchmark->new(
setup => sub {
my ($self, $id) = @_;
$redis->del("key:$id");
$redis->lpush("key:$id", 1..$count);
},
benchmark => sub {
my ($self, $id) = @_;
$redis->lindex("key:$id", $count-1);
return 1; # lindex
},
concurrency => 4,
);
$bm->run();
}
for my $count(@n) {
infof 'lindex: %d', $count;
bench_lindex $count;
}
sub bench_lpushpop {
my $count = shift;
my $bm = Parallel::Benchmark->new(
setup => sub {
my ($self, $id) = @_;
$redis->del("key:$id");
$redis->lpush("key:$id", 1..$count);
},
benchmark => sub {
my ($self, $id) = @_;
$redis->lpush("key:$id", 'a');
$redis->lpop("key:$id");
return 2; # lpush + lpop
},
concurrency => 4,
);
$bm->run();
}
for my $count(@n) {
infof 'lpush & lpop: %d', $count;
bench_lpushpop $count;
}
表1はMacBook AirLPUSH
コマンドやLPOP
コマンドはデータ量の大小にかかわらず速度はほとんど変わりませんが、LINDEX
コマンドはデータ量が大きくなると遅くなっていることがわかります。
リストの長さ | LINDEXコマンドの 1秒あたりの実行数 | LPUSH、 の1秒あたりの実行数 |
---|---|---|
1 | 55,781 | 55,884 |
10 | 52,951 | 55,535 |
100 | 53,715 | 52,476 |
1,000 | 51,025 | 56,889 |
10,000 | 25,954 | 56,636 |
100,000 | 3,171 | 55,930 |
1,000,000 | 315 | 53,764 |
このような計算量の違いを意識しておかないと、
メモリ使用量
Redisはインメモリで動作するため、
さらに、
まとめ
Redisを活用するための代表的なCPANモジュールと、
さて、
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/
定価1,628円
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、 NFT