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

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
默认情况下,缓存在产品模式下会被启动,上面的设置将在开发环境下启动缓存。

4、Page Caching,页面缓存
页面缓存是最快速的一种缓存应用。那么应该在什么时候使用他呢?
1、对于所有用户都相同的页面
2、公开的页面,没有用户认证的页面
如果你的应用中有符合上述条件的,请继续阅读下面的部分。如果你的应用中没有,那么也请继续阅读,下面的内容更精彩(ps:我觉得全世界的广告都一样,不过郁闷的是deyeb目前没有一个页面符合上面的条件,除了404和500吧)

假设我们正在设计一个blog系统,页面并不经常变化,那么我们的controller可能这样来写:



class BlogController < ApplicationController
  def list
     Post.find(:all, :order => "created_on desc", :limit => 10)
  end

  ...
可以看到,List这个action是查询最近的10篇blog文章,对应的web页面上将会显示查询的结果。
如果我们要对这个页面进行缓存的话,只需;


class BlogController < ApplicationController
   caches_page :list  
   def list
     Post.find(:all, :order => "created_on desc", :limit => 10)
   end

  ...
”caches_page“将会在下次请求list这个action时,将页面内容存入一个html页面,放置在一个缓存目录里。

当你在mongrel里第一次运行该代码,访问这个页面的时候,你会在 /logs/development.log log日志中发现下面的代码:

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 10
Rendering blog/list
Cached 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]

注意这一句:Cached page: /blog/list.htm,
这说明,这个页面已经被加载,而且最终你看到的html页面已经被储存在 /public/blog/list.htm 这个位置,如果你检查一下这个页面的话,你会发现上面没有一行ruby代码。

以后,如果当有访问同样的url地址的时候,加载的将是这个html页面,而不适重新加载这个controller中的action(译者:这样说更清 楚)。想像的到,加载一个静态的页面可是比加载并处理一个解释性语言要快得多,几乎快上100倍!(ps:这是真对大访问量情况下的有效的解决办法,同时 也是普通网站的一个很好的设计架构。)

但是只得注意或提醒的是,这样一个静态页面是没有执行任何ruby代码的。所以,当你的页面需要反应一些及时的用户信息,或者当前的信息,你就不能采用这种页面缓存,而是采用局部缓存。这个将在第二部分有讲解。

回到我们的model,


caches_page :show
你猜,当我们访问某一篇具体的文章,比如"/blog/show/5“时,这个页面会被缓存在哪里?
答案是 这里:/public/blog/show/5.html
下面的例子说明页面缓存的位置

http://localhost:3000/blog/list => /public/blog/list.html
http://localhost:3000/blog/edit/5 => /public/edit/5.html
http://localhost:3000/blog => /public/blog.html
http://localhost:3000/ => /public/index.html
http://localhost:3000/blog/list?page=2 => /public/blog/list.html
注意:第一行和最后一行的缓存文件是同一个,页面缓存是忽略掉url地址上的参数的。


5、如何缓存我的分页
为了缓存不同的页面,你需要不同的地址。(译者:我疯了,这个问题没想到,继续看吧)因为页面缓存的时候会忽略掉像/blog/list?page=2这样的参数,所以你需要使用/blog/list/2这样的地址形式,而原来我们使用的是id保存参数值,现在我们需要用page来保存参数值。
下面我们修改 /config/routes.rb文件

map.connect 'blog/list/:page',
    :controller => 'blog',
    :action => 'list',
    :requirements => { :page => /\d+/},
    :page => nil

使用了新的routes定义,我们的连接也应该改成


<%= link_to "Next Page", :controller => 'blog', :action => 'list', :page => 2 %>

最终的连接结果是"/blog/list/2",当我们点这个连接的时候,后台会处理两件事情
1、应用将2放入page这个参数中,而不是原来id这个参数
2、缓存将生成 /public/blog/list/2.html 这个页面

所以,缓存分页,就要将页面参数变成页面的一部分,而不要使用地址参数的形式,他是会被忽略的。

6、清除缓存
看完上面的内容后你可能想问,如果我添加完一篇新的文章到博客,该如何刷新/blog/list这个action呢?
来,看一下我们几分钟前创建的/blog/list.html 页面,它并不包含我们新创建的那个新文章。为了删除这个缓存,并生成一个新的缓存,我们需要让这个页面过期。为了是上面的两个页面过期,我们需要做:


#
 This will remove /blog/list.html
expire_page(:controller => 'blog', :action => 'list')

# This will remove /blog/show/5.html
expire_page(:controller => 'blog', :action => 'show', :id => 5)

显然我们需要在每一个执行了添加,删除,修改的地方粘贴上面的代码,但是还有一个更好的方法来解决问题。
(译者:头一次翻译这么长的文章,上面写的大家能看明白吗?百度空间发表的这篇文章是首发,完成后会在几个地方转载,大家多提意见)

7、Sweepers,缓存自动清理
sweepers是一段自动删除旧的缓存的代码。为了实现这个功能,sweepers需要跟踪你的models,当你的model执行了增删改后,sweepers就会执行上面的命令。
sweepers可以在你的controllers目录创建,但是我觉得他应该隔离开。你可以在/config/environment.rb.进行个设置:


Rails::Initializer.run do |config|
   # ...
   config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )
   # ...
end

ps:记得重启你的服务
这样,你就可以在/app/sweepers 这个目录创建你的sweepers了。/app/sweepers/blog_sweeper.rb
的代码可以这样来写:


class 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)
  end
end

提示:我们可以使用“after_save”替代“after_create”和“after_update”,你自己来试一下吧!
我们还需要告诉我们的controller什么时候调用了sweepers,所以在controller中需要加入:
class BlogController < ApplicationController
   caches_page :list, :show
   cache_sweeper :blog_sweeper, :only => [:create, :update, :destroy]

   ...
好了。我们可以尝试着添加一个新文章,这样在logs/development.log:中你会发现


Expired page: /blog/list.html (0.00000)
Expired page: /blog/show/3.html (0.00000)
我们的sweepers已经工作了!
(译者:这是本文的第一个重要知识)


8、rails缓存与Apache/lighttpd的配合应用(deyeb关注的事情)
当我们将rails应用部署到产品环境的时候,我们多数采用的是apache服务器作为rails服务的前端,将rails请求转发到rails服务器上(Mongrel 或 Lighttpd)。因为我们使用了缓存静态文件的方法,所以我们需要告诉apache服务器,服务请求的是否存在静态页面缓存,如果有,则直接读取静态文件,而不用请求rails服务器了。(deyeb的设计如果这么简单就好啦)
httpd.conf的配置

<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>

lighttpd 的配置写法


server.modules = ( "mod_rewrite", ... )
url.rewrite += ( "^/$" => "/index.html" )
url.rewrite += ( "^([^.]+)$" => "$1.html" )

代理服务器将会查看你放置在 /public 目录下的静态文件,但是你可能想将这个缓存位置改变一下,以保持独立性。那就继续看下面的介绍。


9、更改你的缓存放置位置
首先需要在你的 /config/environment.rb 中添加下面的代码

config.action_controller.page_cache_directory = RAILS_ROOT + "/public/cache/"

这是告诉rails服务你需要将缓存文件放置在/public/cache这个目录下,你还需要重写一下httpd.conf规则。

  # Rewrite index to check for static
  RewriteRule ^/$ cache/index.html [QSA]

  # Rewrite to check for Rails cached page
  RewriteRule ^([^.]+)$ cache/$1.html [QSA]


10、清除你的局部或整体缓存
(原文写的太啰嗦)当你采用了缓存技术时,有时候可能在增删改一个model的时候,需要过期所有的页面缓存,比如当你的所有页面都包含一个最新文章列表的时候。
一个方法是删除你所有的缓存文件,首先可以像上面介绍的那样,移动你的缓存目录,然后按照下面的方法写一个sweepers
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
  end
end

FileUtils.rm_r 将会删除你所有的缓存文件,当然你也可以逐步删除你的缓存,比如当你想删除/public/blog下面的缓存时,可以:

cache_dir = ActionController::Base.page_cache_directory
FileUtils.rm_r(Dir.glob(cache_dir+"/blog/*")) rescue Errno::ENOENT

如果你觉得File Utilities对你实在难于把握,你可以尝试一下 Charlie Bowman 的 broomstick plugin
只需一个简单的调用,就可以删除你每一个controller或action缓存。
(译者:有必要也会翻译一下上面的这篇文章《Modules, Mixins and Inheritance》,直译 为 组件,混入,和继承,但是这样的计算机编程属于还是用英文的好)

11、更高级的缓存?
页面缓存对于像deyeb这样的大型网站,是比较复杂的。(译者:要了朕的亲命了,不然也不会翻译写外文寻找光明了!)下面还有一些其他的方法
Rick Olson (aka Technoweenie)写了个 Referenced Page Caching Plugin ,可以使用数据库表进行页面缓存。
Max Dunn 写了篇非常好的文章,Advanced Page Caching ,教你如何根据用户的角色,使用cookies进行缓存应用的。
最后,貌似没有发现页面缓存xml文件的好方法,Mike Zornek的wrote about his problems 指出了一个处理方法。Manoel Lemos way to do it using action caching
我们将在下一章介绍action缓存。

12、如何测试缓存
没有现成的方法,Luckily Damien Merenne 有一个 swank plugin ,看一下吧。

13、本章结束
页面缓存应该在你的应用中广泛的使用,毕竟它可以提供很快的相应速度。但是当你的项目始终需要进行用户身份验证和身份显示的时候,这样的处理就有局限了!

原文地址:
http://blog.163.com/zhj_mouse/blog/static/6411853720114432550741/
分享到:
评论

相关推荐

    Rails缓存架构设计

    高性能web应用缓存架构设计浅谈 大规模,高并发的访问请求 服务的高可用性 平滑的deployment 良好的可伸缩性

    使用Aptana+Rails开发Rails Web应用(中文)

    例如,要在Rails应用中创建一个新的资源,如博客文章,你需要在models目录下创建一个名为`post.rb`的文件,定义Post类,并设置属性如标题和内容。在controllers目录下创建`posts_controller.rb`,定义控制器方法,如...

    rails_apps_composer, 一个 gem,为 Rails 启动应用程序创建 Rails 应用程序模板.zip

    rails_apps_composer, 一个 gem,为 Rails 启动应用程序创建 Rails 应用程序模板 Rails 应用编辑器 Rails 应用程序编辑器 gem 安装一个 命令行 工具来从"食谱"的Collection 组装 Rails 应用程序。"你可以使用 rails_...

    Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码。

    综上所述,这个压缩包提供的Depot项目是一个典型的Rails应用实例,适合初学者了解Rails框架的基本结构和敏捷开发流程。通过研究源码,开发者可以学习到如何组织代码、设置数据库、编写控制器逻辑、创建视图模板以及...

    Rails中应用Ext.tree:以中国的省市地区三级联动选择为例

    在Ruby on Rails(Rails)框架中,开发人员经常需要实现各种...通过学习这个实例,开发者可以掌握如何在Rails应用中集成第三方库,处理层级数据,以及创建交互式的前端界面。这对于提升Web应用的用户体验非常有价值。

    Ruby-RecordCache在Rails3中缓存ActiveModelRecords

    **Ruby-RecordCache在Rails3中缓存ActiveModelRecords** Ruby on Rails 是一个流行的Web开发框架,它提供了许多工具和库来优化应用程序性能。在Rails 3中,开发者经常面临数据库查询频繁,导致性能瓶颈的问题。为了...

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

    总的来说,Ruby on Rails 的页面缓存机制是提高 web 应用性能的有效手段,但需要开发者根据实际需求灵活选择和实施。通过了解页面缓存的原理和实践,可以更好地优化 Rails 应用的性能,为用户提供更快的加载速度和更...

    rails应用--导航栏实例工程

    在本项目"rails应用--导航栏实例工程"中,我们将探讨如何在Ruby on Rails框架下构建一个实用的导航栏。Rails是一个流行的开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,使得开发过程更加高效且结构...

    Ruby-GoOnRails使用Rails生成器来生成一个Golang应用

    `GoOnRails`是专门为Rails开发者设计的一个生成器,它允许在Rails应用中集成Go代码,创建Go API服务。这个工具简化了在Rails项目中使用Go进行后端处理的流程,使开发者可以利用Go的性能优势处理高并发请求,同时保留...

    应用Rails进行敏捷Web开发中文第三版

    9. **部署**:如何将Rails应用部署到如Heroku或AWS等云平台,以及配置Nginx或Apache作为前端服务器。 通过学习《应用Rails进行敏捷Web开发》中文第三版,你不仅能掌握Rails 2.2.2的基本用法,还能深入理解Web开发的...

    应用Rails进行REST开发

    应用Rails进行REST开发.pdf Restful Rails Development

    Ruby on Rails安装指南(Ruby 1.8.6+Rails 2.0.2)

    最后,创建测试的 Rails 应用程序,并启动 Mongrel 服务器。 知识点1:Ruby 安装 * 下载 Ruby One-Click Installer 版本 * 安装 Ruby * 检查 Ruby 版本 知识点2:Rails 安装 * 下载 Rails 2.0.2 版本 * 安装 ...

    rails3-mongoid-devise, 示例 Rails 3.2应用,带有数据 Mongoid,用于验证.zip

    rails3-mongoid-devise, 示例 Rails 3.2应用,带有数据 Mongoid,用于验证 Rails 4.1有关设计的Rails 4.1示例应用程序,请参见:rails设计有一个用于设计的教程:Rails 设计教程。类似示例和教程这是来自 RailsApps...

    Ruby+on+Rails快速Web应用开发实战.pdf

    Ruby+on+Rails快速Web应用开发实战.pdf

    webpack-rails, 将 web pack与你的Ruby on Rails 应用程序集成.zip

    webpack-rails, 将 web pack与你的Ruby on Rails 应用程序集成 不再维护webpack-rails 不再被维护。 有关详细信息,请参阅 #90. web pack-railsweb pack 为你提供了将 web pack集成到现有的Ruby on Rails 应用程序中...

    rails 部署 nginx

    在部署Rails应用时,还需要考虑性能优化,比如启用HTTP缓存,调整Nginx的连接超时时间,配置Rails应用的线程池大小,以及使用如 unicorn 或 puma 这样的多进程或多线程服务器。 7. **部署工具**: 为了自动化部署...

    rails-prelaunch-signup, web启动预启动站点的Rails 3.2应用程序示例.zip

    rails-prelaunch-signup, web启动预启动站点的Rails 3.2应用程序示例 Rails 应用程序用于启动预启动注册站点Rails 3.2示例应用程序"测试版即将启动"启动预启动注册站点示例应用程序。Rails 预启动注册应用程序插件...

    railsAPI

    至于性能优化,Rails提供了缓存机制,包括页面缓存、片段缓存和动作缓存,以减少服务器负载。还可以利用ActionCable实现WebSocket通信,实现实时数据传输。 最后,Rails API的应用往往需要与前端框架如React、Vue....

    Rails预加载程序Spring-Rails.zip

    Spring是Rails的预加载器。Spring 能够通过保持应用运行在后台,来提升开发模式下的速度。使得不需要在执行test,rake task以及migration时每次都加载。 标签:Spring

Global site tag (gtag.js) - Google Analytics