`
andyhu1007
  • 浏览: 199444 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Rails每周一题(十一): Rails Caching

阅读更多

上次讲到一篇关于web浏览器的cache ,而本篇要讲述的是web服务器端的cache。

 

Web服务器端的cache通过减少对web应用程序的访问和对数据库的访问来减少服务端的负载以及提升客户端的响应速度。

 

Rails本身提供了对web服务器端cache的很好支持,当然还有一些更加方便的plugin如cache_fu

 

Cache需要关注的问题有几点:

 

1. Cache对象

 

2. 在何时以及如何清理cache

 

3. Cache的存储规则

 

4. Cache的存储方式

 

在来研究这几点之前,首先打开rails的cache。

 

打开Rails的cache很简单,只要在环境对应的配置文件config/environments/*.rb中设置即可:

 

config.action_controller.perform_caching = true 
 

接下来让我们来一点点看一下Rails如何处理这些问题。

 

 

Cache对象

 

Cache对象可以是page,action或者一个fragment。

 

 

a. Page cache

 

Page cache是最高效的cache机制,对页面的请求完全由web服务器处理,而不需要经过rails应用程序。

 

让我们通过一个例子来看看rails如何处理page cache:

 

class ProductsController < ActionController 
  caches_page :index  
  def index; end 
end 

 

caches_page方法启动这个page cache。在第一次访问products/index时,rails会生成一个文件index.html。对于接下来的request,web服务器会用这个文件来响应请求。

 

 

缺点:

 

1. 适用面比较窄,比如对于需要认证的页面就无法处理。

 

2. Page cache会忽略参数。如果客户端访问/products/list?page=1,rails会把页面缓存成:/products/list.html。如果客户端下次访问/products/list?page=2时,也会返回/products/list.html。

 

 

b. Action cache

 

我们已经看到,page cache不能处理需要认证的页面。Action cache就是为了解决这个问题,action cache与page cache的区别在于:request会经过web server并且被rails application接收,直到所有的before filters被处理。

 

例子:

 

class ProductsController < ActionController
  before_filter :authenticate, :only => [ :edit, :create ] 
  caches_page :index  
  caches_action :edit  

  def index; end  

  def edit; end 

end 
 

 

c. Fragment cache

 

   动态web应用程序的页面往往由多个components组成,而每个component经常需要采取不同的cache、expire策略。针对这个问题,rails提供了fragment cache。

 

   比如对于这个页面:

 

 

<% Order.find_recent.each do |o| %>  
   <%= o.buyer.name %> bought <% o.product.name %> 
<% end %> 

<% cache do %> 
   All available products: 
   <% Product.find(:all).each do |p| %>  
     <%= link_to p.name, product_url(p) %>  
   <% end %> 
<% end %> 
 

  我们没有cache需要实时更新的order部分,而cache了product list部分。

 

  这个cache块会绑定到相应的action,cache页面也会存于相应的action目录下。所以如果一个页面有多个component被cache,则需要添加suffix来区分它们:

 

 

<% cache(:action => 'recent', :action_suffix => 'all_prods') do %> 
  All available products: 
  ...
 

  也可以无需绑定到相应的action,而赋予一个全局的key:

 

 

<% cache(:key => ['all_available_products', @latest_product.created_at].join(':')) do %>
  All available products: 
<% end %> 

 

清理cache

 

 对于上面几种情况,都有相应的cache清理方法。

 

 比如对于page cache和action cache,可以通过在需要清理的action里面调用expire方法来清理:

 

 

def create 
  expire_page :action => :index  
  expire_action :action => :edit  
end 
 

 Fragment cache的清理则是这样:

 

 

expire_fragment(:controller => 'products', :action => 'recent',  :action_suffix => 'all_prods) 

expire_fragment(:key => ['all_available_products', @latest_product.created_at].join(':')) 
 

 但如上面这样到处写expire方法,显然不是最好的方式。Rails针对此提供了sweeper机制:把cache清理移入一个observer类,此类会监测一个对象的变化,并且通过相应的钩子来清理此对象相关的cache。

 

 

class StoreSweeper < ActionController::Caching::Sweeper 
  # This sweeper is going to keep an eye on the Product model  
  observe Product 

  # If our sweeper detects that a Product was created call this  
  def after_create(product)  
     expire_cache_for(product)  
  end  

   # If our sweeper detects that a Product was updated call this  
   def after_update(product)  
     expire_cache_for(product)  
   end  

   # If our sweeper detects that a Product was deleted call this  
   def after_destroy(product)  
     expire_cache_for(product) 
   end  

   private 

   def expire_cache_for(record)  
     # Expire the list page now that we added a new product    
     expire_page(:controller => '#{record}', :action => 'list')  

     # Expire a fragment  
     expire_fragment(:controller => '#{record}',  :action => 'recent', :action_suffix => 'all_products')  
   end 
end 
 

  Cache sweeper在controller里面就是一个after或者aroud filter:

 

 

class ProductsController < ActionController 
  before_filter :authenticate, :only => [ :edit, :create ] 
  caches_page :list  
  caches_action :edit  
  cache_sweeper :store_sweeper, :only => [ :create ] 

  def list; end  

  def create 
  end  

  def edit; end 
end 

 

 

 Cache的存储规则

 

 Cache的存储规则即如何存储cache文件,即cache的存储路径和文件名。

 

 我们可以告诉rails我们想要的存储路径,当然,大部分的时候rails已经有默认的存储路径。而且在不会产生冲突的时候,我们也不需要重新设定。

 

 Page cache:

 

class WeblogController < ActionController::Base
  caches_page :show, :new
end
 

 Page cache生成的cache文件路径类似于:weblog/show/5.htmlweblog/new.html。

 

 Action cache 和 Fragment cache:

 

 Action cache本质上是在fragment cache的基础上加上一个around filter实现的。所以,它的cache文件名命名规则和fragment cache是一样的:根据host和当前路径。所以,一个url: www.somesites.com/lists/show/1 对应的action cache路径是“www.somesites.com/lists/show/1”。

 

 当一个action有多个不同的路由,它们需要cache到不同的路径时,我们可以通过设定:cache_path选项来根据不同的情况指定cache路径:

 

 

caches_action :feed, :cache_path => Proc.new { |controller|
      controller.params[:user_id] ?
        controller.send(:user_list_url, controller.params[:user_id], controller.params[:id]) :
        controller.send(:list_url, controller.params[:id]) }
 

  对于action cache,我们需要区分不同路由的情况。而对于fragment cache,我们需要区分同一个action下的多个fragments的情况,或者是当这个action已经有action cache(占用了默认路径)时:

 

 

<% cache(:action => "list", :action_suffix => "all_topics") do %>

# 这会使cache存储于"/topics/list/all_topics",以区分使用了不同suffix的fragments。

expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics")

 

 Cache存储方式

 

 Rails提供了多种cache存储方法。

 

 a. ActiveSupport::Cache::MemoryStore

 

    在同一进程的内存中保存cache,所以如果有多个rails application,它们之间不能共享cache。

 

ActionController::Base.cache_store = :memory_store 

 

  b. ActiveSupport::Cache::FileStore

 

    磁盘存储,这是默认的cache存储方式:

 

ActionController::Base.cache_store = :file_store, "/path/to/cache/directory" 
 

  c. ActiveSupport::Cache::DRbStore

 

     Cache存储于一个单独的共享DRb进程,所有的服务器都可以和这个进程通信。但需要维护一个额外的进程:

 

ActionController::Base.cache_store = :drb_store, "druby://localhost:9192" 

 

  d. MemCached

 

    这种方式跟DRb相似,并且是最流行的production cache方式。

 

    它有几大特性:

  • 群组和负载均衡:多个memcached服务器可以进行负载均衡。
  • 支持基于时间的过期机制。
  • 等。。。

  e. ActiveSupport::Cache::SynchronizedMemoryStore

 

    相较于MemoryStore,这是一种线程安全的cache存储。

 

  f. ActiveSupport::Cache::CompressedMemCacheStore

 

    相较于MemoryStore,它对所cache的文件进行了压缩。

 

  g. 自定义cache存储

 

ActionController::Base.cache_store = MyOwnStore.new("parameter") 
 

 

更多内容请参考:http://guides.rubyonrails.org/caching_with_rails.html

 

http://api.rubyonrails.org/classes/ActionController/Caching/Pages.html

 

http://api.rubyonrails.org/classes/ActionController/Caching/Actions.html

 

http://api.rubyonrails.org/classes/ActionController/Caching/Fragments.html

分享到:
评论
2 楼 huacnlee 2009-06-25  
一直都还没搞明白Sweeper和Observe的关系
1 楼 netfork 2009-06-25  
在知识库里申请个专栏如何?

相关推荐

    rails查询学习笔记

    9. **Caching**:为了提高查询效率,Rails支持查询缓存,可以缓存特定查询的结果,避免重复执行相同的数据库操作。 10. **SQL注入防范**:Rails通过绑定参数的方式防止SQL注入,如`Model.where(id: params[:id])`,...

    RAILS2.1的中文版资料

    《RAILS2.1的中文版资料》是一份针对Ruby on Rails 2.1版本的详细介绍文档,由Carlos Brando和Marcos Tapajós共同编写,并由中国Rails社区成员翻译成中文版。该文档详细介绍了Rails 2.1版本中引入的新特性和改进之...

    ruby on rails 3 tutorial.pdf

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

    Agile Web Development with Rails 4

    Examples use Concerns, Russian Doll caching, and Turbolinks, and the book focuses throughout on the right way to use Rails. Additionally, this edition now works on Ruby 2.0, a new release of Ruby ...

    Rails.Angular.Postgres.and.Bootstrap.2nd.Edition

    Create reusable components that bring Bootstrap and Angular together and effectively use materialized views for caching within Postgres. Get your front end working with Webpack, use Postgres' ...

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

    1. **启用页面缓存**:在 Rails 中,启用页面缓存只需要一行代码,通常在 `config/environments/production.rb` 文件中设置 `config.action_controller.perform_caching = true`。然后在控制器中使用 `cache_page` ...

    rubyonrails

    Ruby on Rails(简称Rails)是一种基于Ruby编程语言的开源Web应用程序框架,它遵循Model-View-Controller(MVC)架构模式。Rails强调“约定优于配置”(Convention over Configuration)和“Don't Repeat Yourself”...

    Ruby Rails 3 Linda

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson基于Ruby语言开发的一个开源Web应用程序框架。Rails遵循MVC(模型-视图-控制器)架构模式,致力于“约定优于配置”和“Don't Repeat Yourself”(DRY)的...

    Ruby On Rails开发实例-源代码

    Ruby on Rails(简称RoR或Rails)是一种基于Ruby语言的开源Web应用框架,它遵循Model-View-Controller(MVC)架构模式,旨在使Web开发更简洁、高效。本实例将帮助你深入理解和实践Rails的开发流程。 首先,让我们从...

    actionpack-page_caching:Action Pack的静态页面缓存(从Rails 4.0的核心中删除)

    actionpack-page_caching Action Pack的静态页面缓存(从Rails 4.0的核心中删除)。 介绍 页面缓存是一种缓存方法,其中,响应主体存储在Web服务器可以直接提供服务的文件中: 对端点E的请求到达。 计算其响应并...

    Beginning Ruby on Rails

    Ruby on Rails is the revolutionary online programming tool that makes creating functional e-commerce web sites faster and easier than ever. With the intuitive, straightforward nature of Ruby and the ...

    middleman-fragment-caching:中间人片段缓存扩展,如Rails

    中间人片段缓存像Rails这样的Middleman片段缓存扩展。目的当我们需要构建许多页面时,片段缓存可以减少构建时间。安装在Gemfile上添加以下行: gem 'middleman-fragment-caching' , '~&gt; 0.0.1' 运行捆绑器: $ ...

    rails-documentation-1-2-1.zip

    标题 "rails-documentation-1-2-1.zip" 暗示这是一份关于 Ruby on Rails 框架的文档,版本为 1.2.1。Ruby 是一种面向对象的编程语言,而 Rails 是一个基于 Ruby 的开源 Web 应用程序框架,遵循 Model-View-...

    Pragmatic.Bookshelf.Advanced.Rails.Recipes.May.2008

    《Pragmatic Bookshelf Advanced Rails Recipes May 2008》是一本专注于Rails高级开发实践的书籍,由Pragmatic Bookshelf出版社于2008年5月出版。这本书主要面向已经熟悉Ruby on Rails基础的开发者,旨在通过一系列...

    Rails_Recipes_with_Source_Code

    《Rails Recipes with Source Code》是一本专注于Ruby on Rails框架实践技巧和源代码解析的书籍。Rails是基于Ruby语言的Web开发框架,以其“约定优于配置”(Convention over Configuration)的理念和“开发人员的...

    Enterprise Rails

    Enterprise Rails is indispensable for anyone planning to build enterprise web services. It's one thing to get your service off the ground with a framework like Rails, but quite another to construct a ...

    Ruby-ActionPack的Action缓存在Rails40中从核心移除

    然而,在Rails 4.0版本中,Action Cache被从ActionPack的核心中移除,这一变动对开发者的影响是深远的,因为它改变了缓存策略和最佳实践。 在Rails 3.x及以前,Action Cache允许开发者标记一个Action,将其结果缓存...

Global site tag (gtag.js) - Google Analytics