我正在使用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下载的文件),这不会干扰我上面的查询缓存?我不希望文件缓存中的条目导致我的查询缓存中的条目被驱逐。
答案 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
现在有两个空缓存:store
和Rails.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。新缓存支持其他选项;有关自定义缓存的详细信息,请查看MemoryStore和Caching with Rails。
此解决方案适用于小型应用。请注意MemoryStore文档中的此评论:
如果您正在运行多个Ruby on Rails服务器进程(如果您使用mongrel_cluster或Phusion Passenger就是这种情况),那么这意味着Rails服务器进程实例将无法彼此共享缓存数据在这种情况下,这可能不是最合适的缓存。