読者です 読者をやめる 読者になる 読者になる

cache_fuプラグイン

インストール

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という名前でした。