2

我正在通过 Memcached 在我的 Rails 项目中实现缓存,特别是尝试缓存侧列块(最近的照片、博客等),目前我让它们每 15 分钟左右使缓存过期。哪个行得通,但是如果我可以做到更新,例如添加,更新或诸如此类的新内容,那会更好。

我在 Memcached http://content.newrelic.com/railslab/videos/08-ScalingRails-Memcached-fixed.mp4上观看了 Scaling Rails 截屏视频,在视频中的 8:27,Gregg Pollack 谈到了智能在 Memcached 中缓存的方式是使用智能键(在此示例中为 updated_at 时间戳)来替换以前缓存的项目,而不必使缓存过期。因此,每当更新时间戳时,缓存都会在寻找新时间戳时刷新,我想。

我在这个例子中使用了我的“最近的照片”侧边栏,这就是它的设置方式......

_side-column.html.erb:

<div id="photos"">
   <p class="header">Photos</p>
   <%= render :partial => 'shared/photos', :collection => @recent_photos %>     
</div>

_photos.html.erb

<% cache(photos) do %>
  <div class="row">
    <%= image_tag photos.thumbnail.url(:thumb) %>
    <h3><%= link_to photos.title, photos %></h3>
    <p><%= photos.photos_count %> Photos</p>
  </div>
</div>

<% 结束 %>

在第一次运行时,Memcached 将块缓存为 views/photos/1-20110308040600 并在页面刷新时重新加载缓存的片段,到目前为止一切都很好。然后我在后端的特定行中添加了一张额外的照片并重新加载,但照片数量没有更新。日志显示它仍在从 views/photos/1-20110308040600 加载,并且没有获取更新的时间戳。我所做的一切似乎与视频所做的相同,我在上面做错了什么?

此外,这个问题还有第二部分。正如您在上面的部分中看到的,为集合调用了@recent_photos 查询(在我的 lib 文件夹中的模块之外)。但是,我注意到即使块被缓存,这个 SELECT 查询仍然被调用。我最初尝试将整个部分包装在一个块中,因为 <% cache(@recent_photos) do %>,但显然这不起作用 - 特别是因为整个集合上没有真正的时间戳,当然它只是个别项目. 如果结果已经被缓存,如何防止进行此查询?

更新 参考第二个问题,我发现除非 Rails.cache.exist? 可能只是我的票,但棘手的是使用时间戳的通配符性质......

更新 2 完全忽略我的第一个问题,我弄清楚了为什么缓存没有刷新。那是因为 updated_at 字段没有被更新。原因是我在父项中添加/删除作为嵌套资源的项目,我可能需要对其实施“触摸”以更新父项中的 updated_at 字段。

但是我的第二个问题仍然存在......即使片段被缓存,主要的@recent_photos 查询仍然被调用......有没有使用cache.exists的方法?定位一个名为 /views/photos/1-2011random 之类的缓存?

4

2 回答 2

2

Rails 缓存的主要缺陷之一是您无法可靠地将缓存组件的控制器和视图分开。我发现的唯一解决方案是将查询直接嵌入到缓存块中,但最好通过辅助方法。

例如,您可能有这样的事情:

class PhotosController < ApplicationController
  def index
    # ...

    @recent_photos = Photos.where(...).all

    # ...
  end
end

第一个直觉是仅在视图需要时才运行该查询,例如测试缓存内容的存在。不幸的是,在您测试缓存内容和实际呈现页面之间的时间间隔内,内容过期的可能性很小,当使用 nil 值时,这将导致模板呈现错误@recent_photos

这是一个更简单的方法:

<%= render :partial => 'shared/photos', :collection => recent_photos %>

不要使用实例变量,而是使用辅助方法。定义您的辅助方法,就像您在控制器内的负载一样:

module PhotosHelper
  def recent_photos 
    @recent_photos ||= Photos.where(...).all
  end
end

在这种情况下,该值被保存,以便对同一个帮助方法的多次调用只会触发一次查询。这在您的应用程序中可能不是必需的,可以省略。毕竟,所有方法都有义务返回“最近的照片”列表。

如果 Rails 支持具有自己关联视图的子控制器,则可以消除很多这种混乱,这是此处使用的模式的一种变体。

于 2011-04-08T20:04:06.417 回答
1

自从提出这个问题以来,我一直在进一步研究缓存,我想我开始准确理解这种缓存技术的价值。

例如,我有一篇文章,通过页面需要的各种东西,包括查询其他表,也许我需要对每篇文章进行五到七次不同的查询。但是,以这种方式缓存文章会将所有这些查询减少到一个。

我假设使用这种技术,总是需要至少有“一个”查询,因为需要有“某种”方式来判断时间戳是否已更新。

于 2011-04-30T17:54:09.587 回答