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

How can I create a second Rails in-memory store cache?

我正在使用 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 下载的文件),它不会干扰我上面的查询缓存?我不希望我的文件缓存中的条目导致我的查询缓存中的条目被逐出。

是的,您可以使用 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. The new cache supports additional options; check MemoryStore and Caching with Rails,以获取有关自定义缓存的更多信息。

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

If you're running multiple Ruby on Rails server processes (which is the case if you're using mongrel_cluster or Phusion Passenger), then this means that Rails server process instances won't be able to share cache data with each other and this may not be the most appropriate cache in that scenario.