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

12

我正在使用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缓存(我需要一个用于存储我从互联网上下载的文件),它不会干扰我上面的查询缓存?我不想让我的文件缓存条目导致我的查询缓存条目被驱逐。

只需要使用不同的密钥吗? - lei liu
如果我使用不同的键,那么单个缓存中是否会出现竞争条目?我不希望用于存储查询的LRU条目被我的文件存储键驱逐...也许我没有理解缓存。 - Dave
1个回答

9

是的,你可以用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

10存储在缓存中:

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

确认数据已被缓存:

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

30 存储在缓存中:

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" }

这些细节来自于这个答案。新的缓存支持额外的选项,可以查看MemoryStore使用Rails进行缓存以获取有关自定义缓存的更多信息。

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

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


1
我正准备回答这个问题,看到你已经回答了。非常好的解释! - Jagjot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接