複数の異なるキャッシュ空間を使える、BitzerStoreを作りました

Tsukasa OISHI

複数の名前付きのキャッシュ空間をRailsで使用できる、 BitzerStoreを作りました。

Railsには、 簡単にキャッシュを扱える仕組みが最初からありますが、キャッシュの保存先はひとつしか選べません。

config.cache_store = :mem_cache_store, "server1", "server2"

この場合、キャッシュストアとしてはMemcachedを指定していて、保存先にはserver1, server2と複数のサーバを指定していますが、全体でひとつのキャッシュ空間となります。

キャッシュの保存先はひとつあれば十分なことがほとんどだと思いますが、場合によっては使いどころによってわけたくなるときがあります。
たとえばアクションキャッシュをいくつか使っていて、ひとつの画面だけデザインの変更をしたのでキャッシュをクリアしたいとき。その画面のキャッシュだけクリアすればいいのですが、キャッシュの保存先はひとつなのでflush_allを行えばすべてのキャッシュが消えてしまいます。大規模なサイトだと負荷が一気に高くなりすぎて、これだけで閲覧障害に陥ることもあります。

BitzerStoreを使えば簡単にキャッシュの保存先をわけることができます。
Gemfileで以下を追加します。

gem "bitzer_store"

次にconfig/environments/*.rbでキャッシュストアの設定をします。

config.cache_store = :bitzer_store, {
  :default => [:mem_cache_store, "server0"],
  :top_page => [:mem_cache_store, "server1", "server2"],
  :cluster_a => [:dalli, "server3"],
  :footer => [:file_store, "/tmp"]
}

キャッシュストアとして:bitzer_storeを指定します。
各クラスタはHashで指定します。Hashのkeyはクラスタ名となります。valueは、通常のキャッシュストアの設定と同じものになります。最初にキャッシュストア名を指定して、以降そのキャッシュストアのオプションを指定します。
Railsが使えるものならなんでも設定可能です。
:defaultは必ず指定しなければなりません。

使い方は簡単です。キャッシュを使用するときにoptionsにキー:sheepの値としてクラスタ名を指定します。

Rails.cache.read("a", :sheep => :cluster_a) #=> Dalliのserver3が使われる

何も指定しない場合は、defaultのものが使われます。

Rails.cache.read("a") #=> Memcachedのserver0が使われる

クラスタ名を間違えたときもdefaultが使われます。

caches_action, fragment_cacheも同様に、optionsにキー:sheepでクラスタ名を指定するだけです。