- Memcachedは色んなサービスで使われていますね。
- ということでPerlからMemcachedを使う方法についてを簡単に書いてみます。
- Cache::Memcached::FastのPODのままじゃないかというツッコミもありますがその通りです。。簡単で使いそうな部分だけを取り上げているので詳しくはPOD見てください。
- ものすごくざっくりいうと分散メモリキャッシュサーバーというもので、メモリ上にデータを保存出来て取り出せるというものです。ファイルに書かれた設定やDBのデータをメモリ上にのせておくことで高速にデータの取得を行うことが出来るようになります。
- 詳しくはgihyo.jpにあるkazeburoさんの連載を見ていただけるとよくわかると思います。
- 以前に書いたGearmanと同様にあくまでメモリ上にデータは保存されるので、使いたい時に立ち上げて終わったら落とすとデータは消えます。
- 何らかの理由でmemcachedが落ちてしまうとデータが全部消えてしまうので、実システムでは消えてもいいデータを選ぶことやDBでの永続化などを考慮する必要があります。ですが逆に個人で試してみるには、落とせばすっきりデータが消えるので気軽に試すことが出来ます。
インストール
- Mac環境で試しています。
- 自分の環境では、いつの間にインストールしていたのか既に/usr/bin以下にインストールされていたのですが、バージョンが1.2.8と古かったため、brewでインストールしてみました。
% brew install memcached
- これで/usr/local/bin以下にインストールされます。
起動
- 今回は試すだけなのでフォアグラウンドで起動します。
% memcached
- 起動するとデフォルトでは11211ポートで待ち受けますのでそこに接続していくことになります。
- vvvオプションを付けて起動すると、色んな情報が出力されるので面白いかもしれません。
% memcached -vvv
Cache::Memcached::Fastをインストール
% cpanm Cache::Memcached::Fast
値をセットして取り出す
- Cache::Memcached::FastのSYNOPSISを見るとnewするところで大量のオプションが指定されていますが、ここではとりあえず最低限のオプションだけで動かしてみます。
#!perl
use strict;
use warnings;
use Cache::Memcached::Fast;
my $memd = Cache::Memcached::Fast->new({
servers => [ { address => 'localhost:11211' }],
});
$memd->add('id' => 'koba04');
$memd->add('age' => 28);
my $id = $memd->get('id');
my $age = $memd->get('age');
$memd->set('age' => 57);
$memd->replace('age' => 28);
- ものすごい簡単にやるとこんな感じでしょうか。「add」と「set」と「replace」辺りが似ていてややこしいかなと思うので、簡単に違いを書いてみます。
- add
- keyがセットされていない場合だけ値をセット出来る。keyが既にある場合は更新されない。
- replace
- keyがセットされている場合だけ値をセット出来る。keyがない場合には追加されない。
- set
- keyがセットされている場合でもされていない場合でも値をセットする。keyがあろうがなかろうが値をセットしたい場合はこれを使えばよさそう。
ハッシュとか配列とかも入れられます。
- スカラーだけでなく、配列とかハッシュも入れられるので便利ですね。
$memd->set('color', [qw/red blue green/]);
my $list = $memd->get('color');
print $list->[0];
$memd->set('song', { radiohead => 'creep', travis => 'turn' } );
my $hash = $memd->get('song');
print $hash->{travis};
- ハッシュの中にさらにハッシュを入れたり配列を入れたりももちろん出来ます。
- このままだとidというkeyを持った値はmemcachedで1つしか持てないことになり不便です。そういう時は、namespaceを指定することで名前空間をつくることが出来ます。
my $memd_user = Cache::Memcached::Fast->new({
servers => [{address => 'localhost:11211'}],
namespace => 'user:',
});
my $memd_item = Cache::Memcached::Fast->new({
servers => [{address => 'localhost:11211'}],
namespace => 'item:',
});
$memd_user->set(1 => 'koba04');
$memd_item->set(1 => 'android');
print $memd_user->get(1) . ':' . $memd_item->get(1);
有効期限をセットする
- setやaddやreplaceなどの値をセットする関数に秒単位で指定することが出来ます。
$memd->set('today', 'fine', 60 * 60 * 24);
まとめてセット、取得したい
- 複数の値を一度にまとめてセットして欲しい場合は、addやsetやreplaceなどに〜_multiというメソッドがあるのでそれを使うことが出来ます。
$memd->set_multi(['key1', 'value1'], ['key2', 'value2', 60 * 24 * 24];
print $memd->get('key1') . ':' . $memd->get('key2');
- 逆にまとめて取得したい場合は、get_multiが使えます。
$memd->set_multi(['a' => 'A'], ['b' => 'B']);
my $res = $memd->get_multi('a','b');
print $res->{a} . ':' . $res->{b};
prepend, append
- すでにセットされている文字列の先頭や末尾に値を追加することが出来ます。
$memd->set('id', 'ba');
$memd->prepend('id', 'ko');
$memd->append('id', '04');
print $memd->get('id');
incr(decr)
- idのようなインクリメントしていく値を作りたい場合に便利です。
$memd->set('id', 0);
print $memd->incr;
print $memd->incr('id', 10);
- 最初に書いたとおり、もし落ちちゃうとインクリメントの情報も消えてしまうので、実際に使うには何らかの方法でどこまで進んだのかを復元できる仕組みが必要になるかと思います。
cas, gets
- 値を取得してその値に基づいて再度セットする際、取得した値が他のクライアントから変更されていないことをチェックしたい場合に使用します。getsで値を取得してcasでセットします。
- casというのはどうやらCheck And Set か Compare And Swapのようです。
$memd->set('money', 1000);
my $res = $memd->gets('money');
my $cas = $res->[0];
my $money = $res->[1];
if ( !$memd->cas('money', $cas, $money + 200) ) {
die '誰がか更新している!';
}
print $memd->get('money');
my $res_after = $memd->gets('money');
my $res_after2 = $memd->gets('money');
$memd->set('money', 2000);
my $res_after3 = $memd->gets('money');
print "before => $res->[0], after => $res_after->[0], after2 => $res_after2->[0], after3 => $res_after3->[0]";
- casは値が更新されたタイミングで更新されることがわかります。
delete, flush_all
- 値を削除する場合はdelete、全部消したい場合はflush_allを使います。
$memd->delete($key);
$memd->flush_all;
newオプション
- 先程も書いたようにnewのオプションはたくさんあります。簡単な例だと上記のようにserversとnamespaceだけでOKだと思います。実稼動させたいときはちゃんとPOD読んで設定するのがいいと思います。
- 日本語を扱い時は下記のようにutf8オプションを付けておくと、decodeされた文字列をセットするときにはencodeされた状態でセットしてくれて、memcachedから値を取り出すときはdecodeされた文字列として取り出してくれるので便利です。
my $memd = Cache::Memcached::Fast->new({
servers => [{address => 'localhost:11211'}],
namespace => 'user:',
utf8 => 1,
});
というわけで
- ここに書いてあるようなことはググったりPOD読めばすぐにわかるわけですが自分で試して覚えたかったので書いてみました。
- データを保存しておく方法としてはファイルに書き出したりDBに入れたりといった方法がありますが、個人的にどちらも事前の準備や後始末、値のセット、取得がちょっと面倒かなと思ったりすることがあります。
- スカラー、ハッシュ、配列程度のデータをちょっと保存しておきたい場合にmemcachedを使うと、上記のように簡単に扱うことが出来て気軽でいいかなと思います。終わればmemcachedを落とせばいいだけですし。
- Gearmanと組み合わせてみると気軽にWeb APIを使ったようなウェブアプリも作れそうですね。気が向いたら例でも書いてみます。