2020年4月25日土曜日

Rails.cache を使って SQL クエリの結果をキャッシュしてみた

概要

前回 Postgres を使って Rails6 に入門しました
今回はそのアプリを使って Rails のクエリキャッシュ機能を使ってみたいと思います
簡単に言えば同じクエリは毎回データベースに問い合わせせずにメモリや Redis にキャッシュするという機能です
Rails のバージョンによって構文や使い方が異なるので注意してください

環境

  • macOS 10.15.4
  • Rails 6.0.2.2
  • Redis 5.0.5

キャッシュの有効化

  • rails dev:cache

キャッシュするクエリをモデルで定義する

  • vim app/models/my_task.rb
class MyTask < ApplicationRecord
  def self.cache_all
    Rails.cache.fetch("#{cache_versioning}/list", expires_in: 30.seconds) do
      MyTask.order(posted_date: "DESC").all.to_a
    end
  end
end

ポイントは最後に to_a を付けて配列として返している点です

コントローラでキャッシュを参照するメソッドを使う

  • vim app/controllers/my_tasks_controller.rb
class MyTasksController < ApplicationController
  protect_from_forgery

  def list
    @my_tasks = MyTask.cache_all
  end

  # 一部省略・・・
end

動作確認

  • rails s

で起動して localhost:3000/my_tasks にアクセスしてみましょう

  • c=0 && while :;do ((c ++)); echo $c; curl localhost:3000/my_tasks > /dev/null 2>&1; sleep 1; done

紹介のアクセスは SQL が発行されていますが 2 回目以降は 30 秒経過するまでは SQL が発行されていないのがログから確認できると思います

おまけ: redis をキャッシュにする方法

上記はメモリ上にキャッシュを持っており参照するのが大変です
そんな場合は redis を使いましょう

redis のインストール

  • vim Gemfile
gem "redis_rails"
  • bundle install

config.cache_store の変更

設定ファイルを変更してオンメモリだったキャッシュ先を redis に変更します
Rails6 では :redis_cache_store, { url: ENV['REDIS_URL'] }

  • vim config/environments/development.rb
    (一部省略)
if Rails.root.join('tmp', 'caching-dev.txt').exist?
  config.action_controller.perform_caching = true
  config.action_controller.enable_fragment_cache_logging = true

  # config.cache_store = :memory_store
  config.cache_store = :redis_cache_store, { url: "redis://192.168.100.1/0" }
  config.public_file_server.headers = {
    'Cache-Control' => "public, max-age=#{2.days.to_i}"
  }
else
  config.action_controller.perform_caching = false

  config.cache_store = :null_store
end

あとは redis を起動してアプリで確認すればキャッシュが redis に作成されていることが確認できると思います

192.168.100.1:6379> keys *
1) "true/list"
192.168.100.1:6379> TTL true/list
(integer) 19

データ自体は圧縮されていて平文では確認が難しい状態になっています
redis のエンドポイントに関する細かい設定は参考サイトにあるドキュメントを確認してください

最後に

Rails6 で Rails.cache を使ってみました
かなり簡単に使えました
リアルタイムでの表示が不要であったりデータがすぐに反映されなくても良いようなビューを扱う場合はかなり使える技だと思います

今回は SQL 文の発行をキャッシュしましたがビューの情報やネスト構造の一部だけをキャッシュするロシアンドールキャッシングなどもありいろいろな情報をキャッシュすることができます

参考サイト

0 件のコメント:

コメントを投稿