Rails:在无效时如何最好地重新填充缓存

时间:2012-03-05 16:15:47

标签: ruby-on-rails ruby-on-rails-3 caching invalidation

对于生成代价高昂的页面或操作,标准的Rails缓存方法会在其基础数据变得过时时使页面/操作无效。然后,当发生缓存未命中并生成页面时,请求该页面的下一个用户必须在那里坐N秒。如果N足够大,这将使该用户感到悲伤。当然,它只是一个用户,但如果失效频繁,我们可能会让很多悲伤的用户。

一种解决方案是,每当我使某些页面/操作无效时,还会触发新版本的页面/操作的呈现并将它们放入缓存中。我需要几个小时的编码来构建我需要的版本。

但当然其他人已经解决了这个问题?我环顾四周,找不到合适的宝石或答案。

谢谢!

3 个答案:

答案 0 :(得分:0)

我认为昂贵的计算不是HTML页面的呈现,而是填充页面所需的查询和/或计算。

正如您所说,当它变得无效时,您应该触发此计算/查询,以便下次访问该页面时它立即可用。

你可以存储各种格式的数据:YAML,Marshal转储,JSON,CSV等。如果你走这条路,我会将它存储在像文件系统或你的数据库那样永久存在的地方,而不是Rails缓存,因为不假定Rails缓存总是包含您的数据。

答案 1 :(得分:0)

终于找到了问题和答案:
问:"Warm Up Cache" on deployment
答:https://stackoverflow.com/a/942774/593053

在此留下我的问题,以便其他人可以跟踪并学习 从我的痛苦。

也相关:Rails 3.2: Pre-render (bake) a new page cache immediately after expiry?

我的完整解决方案是采用以下约定:如果cache=regen位于请求的URL中,则表示生成的页面应填充到缓存中。

对于我想要缓存的控制器,include CacheRegenCacheRegen导致控制器在cache = regen时不从缓存中读取,并且在存储到缓存中时不将cache = regen放入密钥中。

代码为:

module CacheRegen
  def read_fragment(key, options = nil)
    if /cache=regen/.match(key)
      logger.info("forcing cache miss due to param cache=regen, key=#{key}")
      return nil
    end
    super(key, options)
  end

  def write_fragment(key, content, options = nil)
    unless key.sub!(/cache=regen/, '').nil?
      key.sub!(/\?\&/, '?')
      key.sub!(/\&\&/, '&')
      key.sub!(/\?$/, '')
      key.sub!(/\&$/, '')
      logger.info("wrote page to cache with key #{key}")
    end
    super(key, content, options)
  end
end

最后,我将以下代码放在new_pages.rake中:

require 'action_dispatch'

def get_url(sess, url)
      uri = "http://YOURSITE.com/" + url + "cache=regen"
      puts "retrieving " + uri
      foo = sess.get(uri)
      puts "got it. #{foo}, #{sess.response.body.length} bytes"
end

desc "If necessary, generate new versions of the most expensive pages"
task :new_pages => :environment do
    puts "Updating pages..."
    sess = ActionDispatch::Integration::Session.new(Rails.application)
    ["controller1", "controller2", "controller3"].each { |noun|
      get_url(sess, noun + "?")
    }

    puts "done."
end

在我的环境中,我有deploy任务,这取决于new_pages任务。

那里有一些宝石会让所有这些变得更加自动化吗?

答案 2 :(得分:-1)

rails中缓存失效的典型解决方案是扫描程序。它是自动缓存失效的技术。 您可以阅读有关清扫工in this guide

的更多信息