l'essentiel est invisible pour les yeux

Sunday, April 22, 2007

[Rails] ActiveRecord::QueryCacheを実装した。CacheStoreにはmemcachedを使用。

ActiveRecord::QueryCache

ActiveRecordの富豪っぷりに困っている。キャッシュの仕組みが用意されているみたいだが過去の遺物となり使用されていない様子。(See Class::ActiveRecord::QueryCache) だから作った。

ActiveRecordの富豪っぷり

  • ActiveRecord#findではフレーム関数を大量に呼び出し深いスタックを生成する。
  • 毎度引数+同じ値で呼び出されるのに毎度SQLの生成を行う。

そこでキャッシュ戦略でも比較的基本的な、クエリ単位でのキャッシュをおこなうクエリキャッシュとしてActiveRecord::QueryCacheを実装した。引数をキーにしてキャッシュを保存するため、SQLの生成も行わず高速に結果をフェッチすることができる。今後は、エンタープライズでのO/R Mapplerのキャッシュ戦略などを調べてもう少し拡張していく予定。

ActiveRecord::QueryCache

仕様
  • SQL単位ではなくActiveRecord#findに渡された引数をキーとしてキャッシュを保存する。
  • キャッシュの保存先にはmemcachedのみ対応。(2007/4/22現在)
  • メソッド単位でキャッシュのexpiryを設定することはできない。クラス単位で指定する。(改良するかも)


インストール
% sudo apt-get memcached
% sudo gem install memcached-client
% svn co http://shindaita.stiq.net/svn/cache_on_rails/query_cache.rb /path/to/raisapp/lib


Railsで使用する場合
# config/enviroment.rb
require 'query_cache'
CACHE = MemCache.new 'localhost:11211', :namespace => 'rakuto.blogspot.com', , :multithread => true


サンプル
CACHE = MemCache.new 'localhost:11211', :namespace => 'rakuto.blogspot.com'

class Person < ActiveRecord::Base
query_cache :expiry => 10.minutes
end

p Person.find(:all, :conditions => "name like '%'", :cacheable => true)


キャッシュが有効だと引数からSQLを生成することも無く、DBへ参照問い合わせを行うことも無いため高速に結果をフェッチすることが可能である。

キャッシュを削除するメソッドは現在一つだけ用意している。ActiveRecord#delete_all_query_cacheメソッドを使用すると、そのクラスで使用しているキャッシュが全て削除される。(仕組み的にはキーを配列で記録しておいて、その値をフェッチしてキーに該当するキャッシュを全て削除する)

Person.delete_all_query_cache


ActiveRecordで作成, 更新 or 削除があったときにキャッシュを削除する指定を実装。
[Rails] ActiveRecord::QueryCacheにキャッシュの削除に関する指定を実装した。

エラー処理 (2007/4/23日追加)
memcached関連でエラーが発生した場合でもロギングして処理を続行する(通常通りDBへアクセスを行う)サイレンスモードを実装。デフォルトではtrueに設定。

class Person
query_cache :expiry => 3.minutes, :expire_methods => [:create, :update, :destroy], :silence => false
end


TODO
  • キャッシュ戦略についてもう少しバリエーションを増やしたい。
  • memcached以外のCacheStoreへの対応。
  • キャッシュの削除戦略が普通はどうするものなのかよくわからない。詳しい人教えてください。


Bug Fix

AR#findに第一引数(:all, :first)のみ渡した場合のbug fix. (Revision 8)