【问题标题】:How can I create a second Rails in-memory store cache?如何创建第二个 Rails 内存存储缓存?
【发布时间】:2017-09-08 13:53:51
【问题描述】:

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

【问题讨论】:

  • 只使用不同的密钥?
  • 是的,但是如果我使用不同的键,现在单个缓存中是否没有竞争条目?我不希望我的用于存储文件的密钥驱逐用于存储查询的 LRU 条目......但也许我不了解缓存。

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


【解决方案1】:

是的,您可以使用 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 服务器进程实例将无法相互共享缓存数据在这种情况下,这可能不是最合适的缓存。

【讨论】:

  • 我正准备回答这个问题,因为我正在准备我的答案。看到你已经这样做了。很好的解释!
猜你喜欢
  • 1970-01-01
  • 2014-03-10
  • 1970-01-01
  • 2013-09-26
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 2018-05-24
  • 1970-01-01
相关资源
最近更新 更多