ここでは、低レベルキャッシュ(特定の値やクエリ結果をキャッシュする)についてまとめています。
注意: 時間の経過とともにレスポンスが変化するデータのキャッシュについて
時間の経過とともにレスポンスが変わるものをキャッシュする場合は、有効期間(expires_in
)を指定して、一定時間後にキャッシュが無効になるようにする必要があります。
キャッシュにはキャッシュキー
を指定しますが、レコードが変更された際にこのキーも更新されることで、キャッシュが更新されます。
しかし、例えばCoupon.where('expired_at > ?', Time.current)
(有効なクーポンを返す)の場合、レコードの内容は変わらなくても時間の経過とともにレスポンスが変わることが期待されます。有効期限を設定せずにキャッシュを使った場合、レコードの内容が変わらなければキャッシュキー
も更新されないため、永久にキャッシュが更新されないという状況になります。
キャッシュの有効期限(expires_in
)を設定するようにしましょう。
尚、expires_in
は、キャッシュが作られてからの期間です。
はじめに覚えておくこと
-
Rails.cache.fetch
このメソッドで、キャッシュのread/writeが両方出来る。 -
<cache_key>
後述の通り、基本的にRailsが用意しているものを使う。 -
expires_in
キャッシュの有効期限を指定する。
実装例
Rails.cache.fetch(<cache_key>, expires_in: 3.hours) do
...
キャッシュが無かった場合、ここで指定した処理が実行され、結果が返されるとともに、
<cache_key> で指定したキーを使ってキャッシュされる
...
end
キャッシュキーの例
cache_key_with_version
(単一レコードに対するキー)
- 以下の通り、「モデルのクラス名」、「id」、「updated_at」を元に生成される。
> coupon.cache_key_with_version
=> "coupons/1-20191011041439715799"
class Product < ApplicationRecord
def competing_price
Rails.cache.fetch("#{cache_key_with_version}/competing_price", expires_in: 12.hours) do
Competitor::API.find_price(id)
end
end
end
cache_key
(複数レコードに対するキー)
- 以下の通り、「モデルのクラス名」、「query-」、「レコード数」、「updated_atの最大値」を元に生成される。
> coupons.cache_key
(5.9ms) SELECT COUNT(*) AS "size", MAX("coupons"."updated_at") AS timestamp FROM "coupons"
=> "coupons/query-39c9e75f3c3df8d18398e78bc912b37c-6-20191011041439715799"
## テーブル全体を対象とする場合は以下の通り
> Coupon.all.cache_key
class Product < ApplicationRecord
def popular_products
Rails.cache.fetch("#{Product.all.cache_key}", expires_in: 12.hours) do
<do_something>
end
end
end
ログ
キャッシュ・ライト時のログ
Cache write: channels/query-cce0a1bf6d4900cec9cf496202394b05-1-20191016105530000000
(1.5ms) SELECT COUNT(*) AS `size`, MAX(`catalogs`.`updated_at`) AS timestamp FROM `catalogs`
↳ app/controllers/toppage_controller.rb:27
キャッシュ・リード(キャッシュ・ヒット)時のログ
Cache read: catalogs/query-5bef3b48a20fab8e12bcfb3f222f834d-1-20191004025349000000
Cache fetch_hit: catalogs/query-5bef3b48a20fab8e12bcfb3f222f834d-1-20191004025349000000
備考
キャッシュはデフォルトではproduction環境でのみ有効です。
ローカルでキャッシュを使う場合は、対応するconfig/environments/*.rb
ファイルでconfig.action_controller.perform_caching
をtrue
に設定する必要があります。
但し、ここで説明した「低レベルキャッシュ」の動作には影響しません。
config.action_controller.perform_caching値の変更は、Action Controllerコンポーネントで提供されるキャッシュでのみ有効になります。つまり、後述する 低レベルキャッシュ の動作には影響しません。