インストール
cache_fu*1プラグインはActiveRecordの結果をmemcachedにキャッシュしてくれるプラグインです。GitHubで公開されています。
ruby script/plugin install git://github.com/defunkt/cache_fu.git
使い方
サーバーの一覧を取得します。
>> CACHE.servers => [<MemCache::Server: localhost:11211 [1] (NOT CONNECTED)>]
キャッシュに値を保存します。その後、キャッシュから値を取り出します。
>> CACHE.add('foo', 12345) => "STORED\r\n" >> CACHE.get('foo') => 12345
データの保存
キャッシュに値を保存するメソッドとしては
CACHE.add <キー>, <値>[, <有効期限>] CACHE.replace <キー>, <値>[, <有効期限>] CACHE.set <キー>, <値>[, <有効期限>]
の三種類があります。
addは同じキーのデータがストレージ上にない場合のみ、値を保存することができます。
>> CACHE.add('foo', 54321) => "NOT_STORED\r\n"
replaceは同じキーのデータがストレージ上にある場合のみ、値を保存することができます。
>> CACHE.replace('foo', 54321) => "STORED\r\n" >> CACHE.get('foo') => 54321 >> CACHE.replace('bar', 67890) => "NOT_STORED\r\n"
setはどんな場合でも値を保存することができます。
>> CACHE.set('foo', 12345) => "STORED\r\n" >> CACHE.get('foo') => 12345 >> CACHE.set('bar', 67890) => "STORED\r\n" >> CACHE.get('bar') => 67890
有効期限を指定すると、指定した秒数経過後にデータを破棄します。
>> CACHE.set('foo', 12345, 10) => "STORED\r\n" >> CACHE.get('foo') => 12345 ~~ 10秒経過 ~~ >> CACHE.get('foo') => nil
データの取得
キャッシュから値を取り出すメソッドとしては
CACHE.get <キー> CACHE.get_multi <キー1>[, <キー2>, <キー3>, <キー4>, <キー5>, ...]
の二種類があります。
一度に値を取り出すときはget_multiを使うと、getをループで処理するよりも数十倍高速に取り出せるそうです。
>> CACHE.get('key1') => "r" >> CACHE.get_multi('key1', 'key2', 'key3', 'key4', 'key5') => {"key1"=>"r", "key2"=>"u", "key3"=>"b", "key4"=>"y", "key5"=>"!"}
ちょっとベンチマークしてみたところ、7倍弱高速でした。
>> a = []; for i in 1..10000 do; a << "key#{i}"; end => 1..10000 >> for i in 1..10000 do; CACHE.set("key#{i}", i); end => 1..10000 >> t = Time.now; for i in 1..10000 do; CACHE.get("key#{i}"); end; Time.now - t => 4.874864 >> t = Time.now; CACHE.get_multi(a); Time.now - t => 0.740923
データの削除
キャッシュからデータを削除するメソッドとしては
CACHE.delete <キー> CACHE.flush_all
の二種類があります。
flush_allメソッドはキャッシュをすべて削除します。
>> CACHE.delete('foo') => "DELETED\r\n" >> CACHE.flush_all => [<MemCache::Server: localhost:11211 [1] (CONNECTED)>]
インクリメントとデクリメント
incrメソッドとdecrメソッドを使うと、memcached上の特定のキーの値をカウンタのように利用できます。
CACHE.incr <キー>[, <増分>] CACHE.decr <キー>[, <増分>]
>> CACHE.set('foo', 0) => "STORED\r\n" >> CACHE.incr('foo') => 1 >> CACHE.incr('foo') => 2 >> CACHE.decr('foo') => 1 >> CACHE.decr('foo') => 0
代わりにgetメソッドで値を取得することはできなくなります。
>> CACHE.get('foo') MemCache::MemCacheError: incompatible marshal file format (can't be read) format version 4.8 required; 50.32 given from /usr/lib/ruby/gems/1.8/gems/memcache-client-1.8.3/lib/memcache.rb:251:in `load' from /usr/lib/ruby/gems/1.8/gems/memcache-client-1.8.3/lib/memcache.rb:251:in `get' from /usr/lib/ruby/gems/1.8/gems/memcache-client-1.8.3/lib/memcache.rb:887:in `with_server' from /usr/lib/ruby/gems/1.8/gems/memcache-client-1.8.3/lib/memcache.rb:247:in `get'
カウンタとして使うデータはあらかじめ作成しておく必要があります。指定したキーのデータがストレージ上にない場合、nilを返します。
>> CACHE.delete('foo') => "DELETED\r\n" >> CACHE.incr('foo') => nil
値は初めてincrメソッド/decrメソッドを使ったときに初期化されます。もともとの値はそれがたとえ数値であったとしても、無視されます。incrメソッドは1を、decrメソッドは0を返します。
>> CACHE.set('foo', 10) => "STORED\r\n" >> CACHE.incr('foo') => 1 >> CACHE.set('foo', '') => "STORED\r\n" >> CACHE.incr('foo') => 1 >> CACHE.set('foo', '1') => "STORED\r\n" >> CACHE.incr('foo') => 1 >> CACHE.set('foo', 'xyz') => "STORED\r\n" >> CACHE.incr('foo') => 1 >> CACHE.set('foo', 10) => "STORED\r\n" >> CACHE.decr('foo') => 0 >> CACHE.set('foo', '') => "STORED\r\n" >> CACHE.decr('foo') => 0 >> CACHE.set('foo', '1') => "STORED\r\n" >> CACHE.decr('foo') => 0 >> CACHE.set('foo', 'xyz') => "STORED\r\n" >> CACHE.decr('foo') => 0
増分を指定すると、それに従って値を加減します。
>> CACHE.set('foo', 0) => "STORED\r\n" >> CACHE.incr('foo', 5) => 5 >> CACHE.incr('foo', 5) => 10 >> CACHE.decr('foo', 5) => 5 >> CACHE.decr('foo', 5) => 0
補足
cache_fuプラグインはオブジェクトをmemcachedに格納するとき、Marshalクラスによってマーシャリングしたものを格納します。そのため、LibXML::XML::Nodeオブジェクトのようにmarshal_dumpメソッドが定義されていないものは格納することができません。
*1:昔はacts_as_cachedという名前でした。