`
rubyrock
  • 浏览: 23021 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

Ruby on Rails实战之一:巧妙解决页面片段缓存陷阱

阅读更多

Rails的片段缓存fragment cache有一个很隐蔽的陷阱。在Rubyconf China 2009会上,牛人Robin Lu向大家详细讲解了这个陷阱(他演讲的ppt在http://www.scribd.com/doc/15705678/Ruby-on-Rails-Pitfall?autodown=pdf 可以看到),最后也提出了3种解决方案,不过我觉得这3种方案都不太令人满意,下面分享一下我的解决方案。

 

首先,有必要简单介绍一下Rails的这个片段缓存陷阱。大家先看一下代码:

 

#code in the controller

class BlogController < ApplicationController
   def list
       unless read_fragment("/blog/list/articles")
           @articles = Article.find(:all)
       end
   end 
end

#code in the view
<% cache("/blog/list/articles") do %>
  <ul>
  <% for article in @articles do %>
     <li> <p> <%=h(article.body)%> </p></li>
   <% end %>
  </ul>
<% end %>

这是很多人使用片段缓存的做法,大概是受了那本经典教程影响的缘故。在并发量不大的情况下,这段代码不会产生问题,但是在并发量一大很容易会crash,提示信息是@articles未赋值。其原因在于,在action中检查缓存和view中使用缓存中间存在时间间隔。设想一下:一个过程在action中found cache,于是未获取@articles,但是执行到view时,缓存被另外的进程清空了,这个时候使用@articles就会报异常。

 

Robin提到的三种方法是:

1.处理异常,提示用户刷新页面。这种方法对用户体验而言,不友好。

2.在view处理的地方获取@articles。这种方法让view中充斥代码,不优雅。

3.更新缓存内容而不是清空缓存。这种方法需要额外处理,不爽。

 

我的解决方法其实非常简单改写cache方法和fragment_exists?方法,在action中使用fragment_exists?检查缓存,如果找到,就把读到的内容置到实例变量中,在view的cache方法中,使用该实例变量。 多说无益,看一下代码

就明白了。

插件smart_fragment_cache 中的核心代码

module ActionController #:nodoc:
  module Caching
    module Fragments       
      #override fragment_exist?
      def fragment_exists?(name, options=nil)
        @internal_smart_caches ||= {}
        key = fragment_cache_key(name)
        @internal_smart_caches[key] = read_fragment(name, options)    
      end      
      
      #cache_miss?
      def fragment_miss?(name, options=nil)
         !fragment_exists?(name,options)       
      end
      
      #override fragment_for
      def fragment_for(buffer, name = {}, options = nil, &block) #:nodoc:
        if perform_caching
          if cache = smart_read_fragment(name, options)
            buffer.concat(cache)
          else
            pos = buffer.length
            block.call
            write_fragment(name, buffer[pos..-1], options)
          end
        else
          block.call
        end
      end      
      
      #smart_read_fragment
      def smart_read_fragment(name, options=nil)
          key = fragment_cache_key(name)
          (@internal_smart_caches and @internal_smart_caches[key]
) or read_fragment(name, options)     
      end
    end
  end
end
 

使用插件后,刚才的代码改写成

#code in the controller

class BlogController < ApplicationController
   def list
       unless fragment_exists?("/blog/list/articles")
           @articles = Article.find(:all)
       end
   end 
end

#code in the view
<% cache("/blog/list/articles") do %>
  <ul>
  <% for article in @articles do %>
     <li> <p> <%=h(article.body)%> </p></li>
   <% end %>
  </ul>
<% end %>
 

代码只有一处细小变化,action中 read_fragment 变为 fragment_exists?。使用这个方案,有三个好处:

1.检查和使用缓存数据只发生一次,高并发下不会触发异常,更安全;

2.只执行一次获取缓存动作,更高效;

3.不需要额外处理,同时保持了view中代码清洁,更优雅。

 

插件 smart_fragment_cache刚刚写成,目前只针对 Rails 2.3.2版本,先提供附件下载吧,等我弄好后再正式发布出来,希望对大家有帮助。

 

 

 

 

 

 

 

 

分享到:
评论
4 楼 rubyrock 2009-05-24  
@internal_smart_caches 是 @controller对象的实例变量,随着@controller的销毁而销毁。@internal_smart_caches的生命周期和@articles是一样的。

在Rails,每次请求都会生成一个新的@controller对象,请求处理结束后,这个对象就会被废弃了。
3 楼 blogbin 2009-05-24  
好像有个问题,@internal_smart_caches的内容在什么时候会失效,并被清除掉呢?
2 楼 QuakeWang 2009-05-24  
Rails 2.3增加了local_cache,对于memcached的操作会在当前Thread做一个本地缓存,所以在Rails 2.3不会出现这种race condition问题

建议将该插件改成适用于rails 2.3之前的版本。

我们在JavaEye使用的是直接在页面上调用model的方法,虽然没有严格遵循MVC,但是比较简单。
1 楼 mccxj 2009-05-24  
貌似是把cache再放一份到内存做个冗余的意思

相关推荐

    举例理解Ruby on Rails的页面缓存机制

    在 Ruby on Rails 中,页面缓存是一种优化性能的技术,尤其适用于那些内容相对静态或者对用户个性化要求不高的网页。页面缓存的工作原理是将动态生成的 HTML 页面直接保存到服务器的文件系统中,后续的相同请求可以...

    Ruby on Rails入门例子

    Ruby on Rails,简称Rails,是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本篇将通过一个入门实例,深入探讨Rails的基本概念和核心...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

    ruby on rails 101

    《Ruby on Rails 101》是一本介绍Ruby on Rails(简称RoR或ROR)的基础书籍,旨在为初学者提供一个全面而深入的学习框架。本书由Peter Marklund编写,包含了五天课程的演示文稿和相关资料,覆盖了从安装到实际应用...

    Ruby on Rails教程:学习使用Rails进行Web开发Ruby on Rails Tutorial: Learn Web Development with Rails

    本书教您如何使用Ruby on Rails开发和部署真正的,具有工业实力的Web应用程序,Ruby on Rails是为诸如Twitter,Hulu,GitHub和Yellow Pages等顶级网站提供支持的开源Web框架。

    Ruby on Rails Tutorial

    《Ruby on Rails Tutorial》中文版(原书第2版,涵盖 Rails 4) Ruby 是一门很美的计算机语言,其设计原则就是“让编程人员快乐”。David Heinemeier Hansson 就是看重了这一点,才在开发 Rails 框架时选择了 Ruby...

    Ruby On Rails 实战圣经

    Ruby on Rails 实战圣经, PDF 档。

    Ruby on Rails:Rails性能优化与缓存策略.docx

    Ruby on Rails:Rails性能优化与缓存策略.docx

    Ruby on Rails 实战圣经

    Ruby on Rails 实战圣经(网页版) html

    ruby on rails最新版

    Ruby on Rails,简称Rails,是基于Ruby编程语言的一个开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,旨在提高开发效率和代码的可读性。Rails以其“约定优于配置”(Convention over Configuration)...

    Ruby on Rails入门经典代码

    Ruby on Rails,简称Rails,是基于Ruby语言的一个开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本压缩包中的"Ruby on Rails入门经典代码"提供了新手学习...

    ruby on rails视频教程

    ruby on rails视频教程 链接:https://pan.baidu.com/s/10eKsJLllLySXk-b5muV_Qw 密码见文件

    Ruby on Rails安装包全集(Linux)

    Ruby on Rails是一款基于Ruby语言的开源Web开发框架,它遵循MVC(模型-视图-控制器)架构模式,简化了Web应用的开发流程。在Linux环境下安装Ruby on Rails需要一系列的依赖包和步骤,本资源包提供了所需的所有组件,...

    Ruby on Rails 4.0指南:学习Ruby on Rails 4.0和Ruby 2.0的分步指南Ruby on Rails 4.0 Guide: A step by step guide to learn Ruby on Rails 4.0 and Ruby 2.0

    学习Ruby on Rails 4.0的逐步指南。 它包括针对Ruby 2.0.0的基本教程,是为至少了解另一种编程语言并熟悉HTML的程序员编写的。

    提升Ruby on Rails性能的几个解决方案

    Ruby On Rails 框架自它提出之日起就受到广泛关注,在“不要重复自己”,“约定优于配置”等思想的指导下,Rails 带给 Web 开发者的是极高的开发效率。 ActiveRecord 的灵活让你再也不用配置繁琐的 Hibernate 即可...

    Ruby On Rails中文教材(PDF)

    Ruby on Rails,简称Rails,是一款基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在简化Web应用程序的开发。Rails由David Heinemeier Hansson于2004年创建,它提倡“约定优于配置...

    Ruby on Rails实践

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson基于Ruby语言开发的一个开源Web应用程序框架。这个框架遵循“约定优于配置”(Convention over Configuration)的原则,致力于简化Web应用的开发流程,提高...

    ruby on rails在线考试系统

    Ruby on Rails(简称Rails)是一种基于Ruby语言的开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在简化Web开发过程并提高效率。在这个“ruby on rails在线考试系统”中,我们可以探讨以下几...

    ruby on rails 3 tutorial.pdf

    《Ruby on Rails 3 Tutorial》是一本专门为初学者设计的指南,旨在帮助读者快速掌握Ruby on Rails这一强大的Web开发框架。Ruby on Rails(简称Rails)是基于Ruby语言的一个开源框架,它采用MVC(Model-View-...

Global site tag (gtag.js) - Google Analytics