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

Dav*_*ave 11 caching ruby-on-rails in-memory ruby-on-rails-5

我正在使用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
Run Code Online (Sandbox Code Playgroud)

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

ano*_*rmh 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
Run Code Online (Sandbox Code Playgroud)

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

ten    = File.read("10M"); 0
thirty = File.read("30M"); 0
Run Code Online (Sandbox Code Playgroud)

存储ten在缓存中:

Rails.cache.fetch("ten") { ten }; 0
Run Code Online (Sandbox Code Playgroud)

确认数据已缓存:

Rails.cache.fetch("ten")[0..10]
=> "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
Run Code Online (Sandbox Code Playgroud)

存储thirty在缓存中:

Rails.cache.fetch("thirty") { thirty }; 0
Run Code Online (Sandbox Code Playgroud)

确认未保存(太大而无法在作为字符串扩展时保存在缓存中):

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

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

现在有两个空缓存: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"
Run Code Online (Sandbox Code Playgroud)

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

要在应用程序中实现第二个缓存,请创建初始化程序config/initializers/cache.rb并添加:

$cache = ActiveSupport::Cache::MemoryStore.new
Run Code Online (Sandbox Code Playgroud)

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

$cache.fetch("foo") { "bar" }
Run Code Online (Sandbox Code Playgroud)

其中一些细节来自这个答案.新缓存支持其他选项; 有关自定义缓存的更多信息,请查看MemoryStoreCails with Rails.

此解决方案适用于小型应用程序.请注意MemoryStore文档中的这条评论:

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