rails 缓存的应用(转载)
【转载】
当你网站访问量上升的时候,你可能为你的rails项目增加一些缓存应用。这个教程将告诉你关于rails缓存的方方面面,帮助你提高rails应用,而不必再为过度的cpu开销而烦心。
rails缓存有几种方式,这篇教程将分几个部分向你分别介绍如何应用不同的缓存方案,以及一些高级的有针对性的缓存应用。
首先介绍最快速的缓存应用:Page Caching,页面缓存
1、为什么要进行缓存
(如果你已经对缓存的必要性有所了解,可以跳过本段)
ruby是一种解释性语言,这意味着ruby代码在没有被执行前,是不会编译成机器能识别的机器码的。
这个特点和php是一样的,但是java在这方面完全不同(java是先编译成机器码,后运行的)。
所以,当有人访问你的ruby程序的时候,你的代码才被读取并执行,你可以想象一下,当每秒钟有100个人访问你的代码的时候,你的程序将会消耗掉很多的系统资源。
那么改如何解决呢?
(译者:本篇文章讨论的是Rails框架中的缓存机制,Ruby是开发Rails框架的一种语言,和java,c语言一样的。)
2、缓存
缓存是web处理(web应用)中的一个重要的设计策略,它被放置在一个临时的位置。如果有人请求了一个同样的应用,我们就可以为他提供一个应用的缓存版本。
提供一个缓存,不仅可以使我们的应用不用读取任何数据库资源,而且请求可以不必经过我们的rails应用服务。(译者:这句话很有意思,往后面看吧)
在开始缓存设计之前,有一些rails配置需要设定
3、缓存配置
在开始缓存应用前,你需要配置你的/config/environments/development.rb文件
config.action_controller.perform_caching = true默认情况下,缓存在产品模式下会被启动,上面的设置将在开发环境下启动缓存。
class BlogController < ApplicationController def list Post.find(:all, :order => "created_on desc", :limit => 10) end
class BlogController < ApplicationController caches_page :list def list Post.find(:all, :order => "created_on desc", :limit => 10) end
Processing BlogController#list (for 127.0.0.1 at 2007-02-23 00:58:56) [GET] Parameters: {"action"=>"list", "controller"=>"blog"}SELECT * FROM posts ORDER BY created_on LIMIT 10Rendering blog/listCached page: /blog/list.html (0.00000)Completed in 0.18700 (5 reqs/sec) | Rendering: 0.10900 (58%) | DB: 0.00000 (0%) | 200 OK [http://localhost/blog/list]map.connect 'blog/list/:page', :controller => 'blog', :action => 'list', :requirements => { :page => /\d+/}, :page => nil<%= link_to "Next Page", :controller => 'blog', :action => 'list', :page => 2 %>
This will remove /blog/list.htmlexpire_page(:controller => 'blog', :action => 'list')# This will remove /blog/show/5.htmlexpire_page(:controller => 'blog', :action => 'show', :id => 5)
Rails::Initializer.run do |config| # ... config.load_paths += %W( #{RAILS_ROOT}/app/sweepers ) # ...endclass BlogSweeper < ActionController::Caching::Sweeper observe Post # This sweeper is going to keep an eye on the Post model # If our sweeper detects that a Post was created call this def after_create(post) expire_cache_for(post) end # If our sweeper detects that a Post was updated call this def after_update(post) expire_cache_for(post) end # If our sweeper detects that a Post was deleted call this def after_destroy(post) expire_cache_for(post) end private def expire_cache_for(record) # Expire the list page now that we posted a new blog entry expire_page(:controller => 'blog', :action => 'list') # Also expire the show page, incase we just edited a blog entry expire_page(:controller => 'blog', :action => 'show', :id => record.id) endend
class BlogController < ApplicationController caches_page :list, :show cache_sweeper :blog_sweeper, :only => [:create, :update, :destroy]
<VirtualHost *:80> ... # Configure mongrel_cluster <Proxy balancer://blog_cluster> BalancerMember http://127.0.0.1:8030 </Proxy> RewriteEngine On # Rewrite index to check for static RewriteRule ^/$ /index.html [QSA] # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://blog_cluster%{REQUEST_URI} [P,QSA,L] ...</VirtualHost>server.modules = ( "mod_rewrite", ... )url.rewrite += ( "^/$" => "/index.html" )url.rewrite += ( "^([^.]+)$" => "$1.html" )
config.action_controller.page_cache_directory = RAILS_ROOT + "/public/cache/"
# Rewrite index to check for static RewriteRule ^/$ cache/index.html [QSA] # Rewrite to check for Rails cached page RewriteRule ^([^.]+)$ cache/$1.html [QSA]
class BlogSweeper < ActionController::Caching::Sweeper observe Post def after_save(record) self.class::sweep end def after_destroy(record) self.class::sweep end def self.sweep cache_dir = ActionController::Base.page_cache_directory unless cache_dir == RAILS_ROOT+"/public" FileUtils.rm_r(Dir.glob(cache_dir+"/*")) rescue Errno::ENOENT RAILS_DEFAULT_LOGGER.info("Cache directory '#{cache_dir}' fully sweeped.") end endendcache_dir = ActionController::Base.page_cache_directoryFileUtils.rm_r(Dir.glob(cache_dir+"/blog/*")) rescue Errno::ENOENT