如何创建第二个Rails内存存储缓存?

时间:2017-04-12 16:50:40

标签: ruby-on-rails caching ruby-on-rails-5 in-memory

我正在使用Rails 5.我当前正在使用Rails内存缓存来缓存数据库查询结果,例如,这是在我的state.rb模型中......

  def self.cached_find_by_iso_and_country_id(iso, country_id)
    if iso
      Rails.cache.fetch("#{iso.strip.upcase} #{country_id}") do
        find_by_iso_and_country_id(iso.strip.upcase, country_id)
      end
    end
  end

我的问题是,如何创建第二个内存中的Rails缓存(我需要一个用于存储我从Internet下载的文件),这不会干扰我上面的查询缓存?我不希望文件缓存中的条目导致我的查询缓存中的条目被驱逐。

1 个答案:

答案 0 :(得分:8)

是的,你可以用Rails做到这一点。您需要创建第二个缓存并将其作为全局变量在您的应用中使用,然后根据上下文调用适当的缓存。每个缓存都分配了自己的内存块(默认为32 MB),如果一个缓存填满,则不会影响其他缓存。这是通过ActiveSupport::Cache::MemoryStore.new完成的。

我将证明这两个缓存不会相互影响:

首先,生成两个用于测试缓存的文本文件,一个10 MB,一个30 MB:

dd if=/dev/zero of=10M bs=1m count=10
dd if=/dev/zero of=30M bs=1m count=30

打开Rails控制台并将其读入字符串:

ten    = File.read("10M"); 0
thirty = File.read("30M"); 0

ten存储在缓存中:

Rails.cache.fetch("ten") { ten }; 0

确认数据已缓存:

Rails.cache.fetch("ten")[0..10]
=> "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"

thirty存储在缓存中:

Rails.cache.fetch("thirty") { thirty }; 0

确认未保存(太大而无法在以字符串形式展开时保存在缓存中):

Rails.cache.fetch("thirty")[0..10]
NoMethodError: undefined method `[]' for nil:NilClass

确认这已经破坏了整个缓存:

Rails.cache.fetch("ten")[0..10]
NoMethodError: undefined method `[]' for nil:NilClass

现在创建第二个缓存并确认其行为与原始缓存相同:

store = ActiveSupport::Cache::MemoryStore.new
store.fetch("ten") { ten }; 0
store.fetch("ten")[0..10]
=> "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
store.fetch("thirty") { thirty }; 0
store.fetch("thirty")[0..10]
NoMethodError: undefined method `[]' for nil:NilClass
store.fetch("ten")[0..10]
NoMethodError: undefined method `[]' for nil:NilClass

现在有两个空缓存:storeRails.cache。让我们确认它们是独立的:

Rails.cache.fetch("ten") { ten }; 0
Rails.cache.fetch("ten")[0..10]
=> "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
store.fetch("thirty") { thirty }; 0  # bust the `store' cache
Rails.cache.fetch("ten")[0..10]
=> "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"

如果两个缓存受到干扰,则最后一次store.fetch调用会破坏两个缓存。它只会破坏store

要在您的应用中实施第二个缓存,请创建初始值设定项config/initializers/cache.rb并添加:

$cache = ActiveSupport::Cache::MemoryStore.new

使用与Rails.cache相同的方式调用代码中的新缓存:

$cache.fetch("foo") { "bar" }

其中一些细节来自this answer。新缓存支持其他选项;有关自定义缓存的详细信息,请查看MemoryStoreCaching with Rails

此解决方案适用于小型应用。请注意MemoryStore文档中的此评论:

  

如果您正在运行多个Ruby on Rails服务器进程(如果您使用mongrel_cluster或Phusion Passenger就是这种情况),那么这意味着Rails服务器进程实例将无法彼此共享缓存数据在这种情况下,这可能不是最合适的缓存。