2011-04-08 44 views
2

我正在通过Memcached实现缓存到我的Rails项目中,特别是试图缓存侧列块(最近的照片,博客等),目前我让他们每15到期一次缓存分钟左右。哪些工作,但如果我可以做到更新,就像新内容添加,更新或什么时候那样,那会更好。Rails 3和Memcached - 无需智能缓存

我正在观看Memcached http://content.newrelic.com/railslab/videos/08-ScalingRails-Memcached-fixed.mp4上的Scaling Rails截屏视频以及视频中的8:27,Gregg Pollack谈到了Memcached中的智能缓存,其中智能键(在本例中为updated_at时间戳)用于替换先前缓存的项目,而不必使缓存过期。所以无论何时更新时间戳,缓存都会刷新,因为它会查找新的时间戳,我会假设的。

我用我的 “近期照片” sideblock在这个例子中,这是它是如何设置...

_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进行缓存,并在刷新页面时重新加载该缓存片段,到目前为止效果非常好。然后我添加一个额外的照片到后端的特定行并重新加载,但照片数不会更新。日志显示它仍然从视图/照片/ 1-20110308040600加载,而不是抓取更新的时间戳。我所做的一切似乎与视频所做的一样,我上面做错了什么?

另外,这个问题还有第二部分。正如你在上面的部分看到的那样,为集合调用了@recent_photos查询(在我的lib文件夹中的模块之外)。但是,我注意到即使块被缓存,这个SELECT查询仍然被调用。我试图首先将整个部分封装在一个块中,作为<%缓存(@recent_photos)做%>,但显然这不起作用 - 尤其是因为整个集合上没有实时时间戳,仅仅是个别项目。如果结果已经被缓存,我怎么能阻止这个查询呢?

UPDATE 在引用第二个问题时,我发现除非Rails.cache.exist?可能只是我的票,但有什么棘手的是使用时间戳的通配符性质...

更新2 无视我的第一个问题完全,我想通了,究竟为什么缓存不清爽。这是因为updated_at字段没有被更新。原因是我添加/删除了父项中嵌套资源的项目,并且我可能需要实现“触摸”以更新父项中的updated_at字段。

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

回答

1

由于自从问这个问题以来我一直在进一步研究缓存,我想我已经开始明白这种缓存技术的价值了。

例如,我有一篇文章,通过查询其他表格所需的各种东西,包括查询其他表格,也许我需要为每篇文章做五七个不同的查询。但是,以这种方式缓存文章会将所有这些查询都还原为一个。

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

2

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

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

class PhotosController < ApplicationController 
    def index 
    # ... 

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

    # ... 
    end 
end 

第一直觉是只运行该查询是否会被认为是必需的,如测试缓存内容的存在。不幸的是,内容在您测试缓存和实际渲染页面之间的时间间隔内有一个很小的机会,在使用无值@recent_photos时会导致模板渲染错误。

这里有一个简单的方法:

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

使用实例变量,而不是使用一个辅助方法。定义你的辅助方法,因为你会一直控制器内部负载:

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

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

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

+0

我没有我的实例变量在一个控制器,但一个模块,因为我需要调用整个站点(多个控制器)侧边栏块,并受到不同的SO问题指示,以保持这样的逻辑出助手。无论如何,我给了上面的一个尝试,但即使在助手中,每个负载仍然会调用recent_photos。我可以防止这种情况的唯一方法是在缓存块本身内调用recent_photos,但是当更新内容时,缓存区域不会更新。绝对是一个令我困惑的领域,如果无论如何都需要调用查询,那么缓存没有多大意义。 – Shannon 2011-04-08 21:25:28