LoginSignup
3
4

More than 5 years have passed since last update.

memoistとRailsキャッシュのどちらがパフォーマンスが良いか調べてみた

Last updated at Posted at 2015-06-18

memoistとRailsキャッシュのどちらがパフォーマンスが良いか調べてみた

はじめに

Railsでマスター系のDBで何度も同じ内容を叩いたり、N+1問題対策でincludesをつけていても、結局
デカイSQLを発行してしまい効率的ではない場合もある

そこでメモリに保存して再利用する方法memoistを使っては見たものの、普通のRailsについてる機能のLow-Level Cachingを使ってもそんなにパフォーマンスが変わらないんじゃないか?と言う疑問をがふつふつと湧いたので計測して、運用しているサービスでどちらを採用するか決めた

※Railsのキャッシュはmemcacheを使用

検証環境

  • OS: MacOSX 10.10
  • Rails version: 4.2
  • memoist version: 0.12.0

サンプルコード

class SampleCode < ActiveRecord::Base

  #キャッシュされるSampleCodeモデルのコード群
  @@cached_codes = [AAA, BBB, CCC, DDD, EEE].map!(&:freeze).freeze

  # クラスメソッドのメモ化
  class << self
    extend Memoist
    def plan_ids
      SampleCode(code: @@cached_codes).pluck(:id)
    end
    memoize :plan_ids
  end

  # クラスメソッドで、Low-Level Cachingを利用
  def self.plan_ids_cache
    Rails.cache.fetch("plan_ids_cache_key", expires_in: 1.day) do
      SampleCode(code: @@cached_codes).pluck(:id)
    end
  end
end

計測

Rails consoleを起動して下記にある検証コードをコピペして実行する

> bin/rails console 

5つの整数を格納した配列を取得するメソッドが1000回
memoistを使う場合とLow-Level Cachingを使う場合、最後に普通にActiveRecordでデータを取ってくる場合だ

(ベンチマークの試行回数の書き方が間違ってたので修正してあります)

# 開実行する
require "benchmark"

#試行回数
num = 1000

plan_code = [AAA, BBB, CCC, DDD, EEE].map!(&:freeze).freeze

report = Benchmark.bm do |r|
  r.report "memo" do
    num.times { SampleCode.plan_ids }
  end
  r.report "cache" do
    num.times { CampaignCode.plan_ids_cache }
  end
  # ActiveRecordで素でとった場合
  r.report "ar original" do
    num.times { SampleCode.where(code: plan_code).pluck(:id) }
  end
end


# ローカル環境実行結果(memcachedもローカルサーバで動いている)
=>
            user     system   total   real
memo        0.0200   0.0100   0.0300 (0.0332)
cache       0.3299   0.2200   0.5499 (1.1794)
ar original 1.6600   0.2500   1.9100 (4.5657)


=>

# Staging環境実行結果(サーバはHeroku, memcachedはアドオン動いている)

            user     system   total   real
memo        0.0099   0.0      0.0099 (0.1472)
cache       0.5000   0.1499   0.6499 (3.6802)
ar original 1.1500   0.1699   1.3200 (3.3467)


考察

memoistを使った場合圧倒的に早いLow-Level Cachingを用いた場合キャッシュもActiveRecordを直接取ってくる場合よりよりもローカル環境では5倍以上倍早く、stagingでは2倍以上早い。

Staging環境でのテストでもmemcachedが別サーバにあるでのオーバヘッドがあるにも関わらず予想外に好成績だった(むしろHerokuが予想外に早くてびっくりした)

memoistの場合はサーバのメモリに保存するがLow-Level Cachingの場合はmemcacheにキャッシュした値を委譲できるので、少メモリと言う観点ではLow-Level Cachingが優位性がある

結論

使いドコロによってmemoistとLow-Level Cachingを使い分けることにした

  • memoist はバッチ処理など一気に大量のデータを処理する場合に用いる
  • Low-Level Cachingはユーザがよく参照する画面で必要な情報をキャッシュする

refs

Ruby でベンチマークを取る方法

3
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4