我研究了一下memoist和Rails缓存,看哪个性能更好
我调查了一下,想知道Memoist和Rails缓存中哪个性能更好。
首先
在Rails中,即使我们在主数据库上多次执行相同的查询或者使用includes来解决N+1问题,最终可能仍会发出大型的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控制台并将下面的验证代码复制并执行。
> bin/rails console
获取存放了5个整数的数组的方法使用memoist的情况下和使用低级缓存的情况下,以及最后通过普通的ActiveRecord获取数据的情况下,重复1000次。
由于基准测试的执行次数书写方式有误,已经进行修正。
# 開実行する
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)
考察 chá)
如果使用memoist,相比直接通过ActiveRecord获取缓存,采用低级别缓存的速度明显更快,本地环境快5倍以上,staging环境快2倍以上。
在Staging环境进行测试时,尽管memcached放在另一台服务器上会存在额外的开销,但结果出奇地好(甚至让我对Heroku的速度感到惊讶)。
对于memoist而言,它将数据保存在服务器内存中;而对于低级缓存(Low-Level Caching),则可以将缓存的值委托给memcache,因此从内存使用的角度来看,低级缓存具有优势。
得出结论
根据使用情况,我们决定使用memoist和低级缓存来达到不同的目的。
-
- memoist はバッチ処理など一気に大量のデータを処理する場合に用いる
- Low-Level Cachingはユーザがよく参照する画面で必要な情報をキャッシュする
参考文献
使用 Ruby 进行基准测试的方法