`
viva_yang
  • 浏览: 35758 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论
阅读更多
今天插一脚,介绍一下Rails的缓存机制以及memcached的使用
Rails的Cache分四种:
1,Page Cache - Fastest
2,Action Cache - Next Fastest
3,Fragment Cache - Least Fastest
4,ActiveRecord Cache - Only available in Edge Rails
下面一一介绍上面四种Cache以及Rails如何使用memcached

一、Page Cache
如果开发阶段要使用cache,则需要先设置好config/environments/development.rb:
Java 代码

   1. config.action_controller.perform_caching = true 

config.action_controller.perform_caching = true


而production环境下默认是开启cache功能的
Page Cache是Rails中最快的cache机制,使用Page Cache的前提一般为:
1,需要cache的page对所有用户一致
2,需要cache的page对public可访问,不需要authentication
Page Cache使用起来很简单:
Java 代码

   1. class BlogController < ApplicationController 
   2.   caches_page :list, :show 
   3.  
   4.   def list 
   5.     Post.find(:all, \:order => "created_on desc", :limit => 10) 
   6.   end 
   7.  
   8.   def show 
   9.     @post = Post.find(params[:id]) 
  10.   end 
  11. end 

class BlogController < ApplicationController
  caches_page :list, :show

  def list
    Post.find(:all, \:order => "created_on desc", :limit => 10)
  end

  def show
    @post = Post.find(params[:id])
  end
end


这样我们就对BlogController的list和show页面进行了缓存
这样做的效果是第一次访问list和show页面时生成了public/blog/list.html和public/blog/show /5.html这两个html页面
对于分页情况下的cache,我们需要把url的page参数改写成"blog/list/:page"这种形式,而不是"blog /list?page=1"这种形式
这样cache的html页面即为public/blog/list/1.html
当数据更改时我们需要清除旧的缓存,我们采用Sweepers来做是非常不错的选择,这把在BlogController里清除缓存的代码分离出来
首先编辑config/environment.rb:
Java 代码

   1. Rails::Initializer.run do |config| 
   2.   # ... 
   3.   config.load_paths += %w(#{RAILS_ROOT}/app/sweepers) 
   4.   # ... 

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


这告诉Rails加载#{RAILS_ROOT}/app/sweepers目录下的文件
我们为BlogController定义app/sweepers/blog_sweeper.rb:
Java 代码

   1. class BlogSweeper < ActionController::Caching::Sweeper 
   2.   observe Post # This sweeper is going to keep an eye on the Post model 
   3.  
   4.   # If our sweeper detects that a Post was created call this 
   5.   def after_create(post) 
   6.     expire_cache_for(post) 
   7.   end 
   8.  
   9.   # If our sweeper detects that a Post was updated call this 
  10.   def after_update(post) 
  11.     expire_cache_for(post) 
  12.   end 
  13.  
  14.   # If our sweeper detects that a Post was deletedcall this 
  15.   def after_destroy(post) 
  16.     expire_cache_for(post) 
  17.   end 
  18.  
  19.   private 
  20.   def expire_cache_for(record) 
  21.     # Expire the list page now that we posted a new blog entry 
  22.     expire_page(:controller => 'blog', :action => 'list') 
  23.  
  24.     # Also expire the show page, in case we just edit a  blog entry 
  25.     expire_page(:controller => 'blog', :action => 'show', :id => record.id) 
  26.   end 
  27. end 

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 deletedcall 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, in case we just edit a  blog entry
    expire_page(:controller => 'blog', :action => 'show', :id => record.id)
  end
end


然后我们在BlogController里加上该sweeper即可:
Java 代码

   1. class BlogController < ApplicationController 
   2.   caches_page :list, :show 
   3.   cache_sweeper :blog_sweeper, \:only => [:create, :update, :destroy] 
   4.   # ... 
   5. end 

class BlogController < ApplicationController
  caches_page :list, :show
  cache_sweeper :blog_sweeper, \:only => [:create, :update, :destroy]
  # ...
end


我们可以配置cache的静态html文件的存放位置,这在config/environment.rb里设置:
Java 代码

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

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


然后我们设置Apache/Lighttpd对于静态html文件render时不接触Rails server即可
所以Page Cache就是最快的Cache,因为它不与Rails server打交道,直接load静态html

二、Action Cache
Action Cache相关的helper方法是caches_action和expire_action,其他基本和Page Cache一样
另外我们还可以运行rake tmp:cache:clear来清空所有的Action Cache和Fragment Cache
Java 代码

   1. class BlogController < ApplicationController 
   2.   before_filter :authentication 
   3.   caches_action :list, :show 
   4.   cache_sweeper :blog_sweeper, \:only => [:create, :update, :destroy] 

class BlogController < ApplicationController
  before_filter :authentication
  caches_action :list, :show
  cache_sweeper :blog_sweeper, \:only => [:create, :update, :destroy]


如上代码所示,我们将authentication这个filter放在caches_action之前声明,这样我们的Action Cache在执行之前会先访问authentication方法
这样可以弥补Page Cache不能对需要登录认证的Page进行Cache的缺点
生成的cache文件为tmp/cache/localhost:3000/blog/list.cache,这样对不同subdomain的访问页面可以cache到不同的目录
由于每次访问Action Cache时都需要与Rails server打交道,并且要先运行filters,所以比Page Cache的效率稍低

三、Fragment Cache
Fragment Cache用于处理rhtml页面中的部分需要cache的模块,如app/views/blog/list.rhtml:
Java 代码

   1. <strong>My Blog Posts</strong> 
   2. <% cache do %> 
   3.   <ul> 
   4.     <% for post in @posts %> 
   5.       <li><%= link_to post.title, :controller => 'blog', :action => 'show', :id => post %></li> 
   6.     <% end %> 
   7.   </ul> 
   8. <% end %> 

<strong>My Blog Posts</strong>
<% cache do %>
  <ul>
    <% for post in @posts %>
      <li><%= link_to post.title, :controller => 'blog', :action => 'show', :id => post %></li>
    <% end %>
  </ul>
<% end %>


生成的cache文件为/tmp/cache/localhost:3000/blog/list.cache
我们需要在BlogController的list方法里加上一行判断,如果是读取Fragment Cache,则不必再查询一次数据库:
Java 代码

   1. def list 
   2.   unless read_fragment({}) 
   3.     @post = Post.find(:all, \:order => 'created_on desc', :limit => 10) 
   4.   end 
   5. end 

def list
  unless read_fragment({})
    @post = Post.find(:all, \:order => 'created_on desc', :limit => 10)
  end
end


Fragment分页时的Cache:
Java 代码

   1. def list 
   2.   unless read_fragment({:page => params[:page] || 1}) # Add the page param to the cache naming 
   3.     @post_pages, @post = paginate :posts, :per_page => 10 
   4.   end 
   5. end 

def list
  unless read_fragment({:page => params[:page] || 1}) # Add the page param to the cache naming
    @post_pages, @post = paginate :posts, :per_page => 10
  end
end


rhtml页面也需要改写:
Java 代码

   1. <% cache ({:page => params[:page] || 1}) do %> 
   2.   ... All of the html to display the posts ... 
   3. <% end %> 

<% cache ({:page => params[:page] || 1}) do %>
  ... All of the html to display the posts ...
<% end %>


生成的cahce文件为/tmp/cache/localhost:3000/blog/list.page=1.cache
从分页的Fragment Cache可以看出,Fragment Cache可以添加类似名字空间的东西,用于区分同一rhtml页面的不同Fragment Cache,如:
Java 代码

   1. cache ("turkey") => "/tmp/cache/turkey.cache" 
   2. cache (:controller => 'blog', :action => 'show', :id => 1) => "/tmp/cache/localhost:3000/blog/show/1.cache" 
   3. cache ("blog/recent_posts") => "/tmp/cache/blog/recent_posts.cache" 
   4. cache ("#{request.host_with_port}/blog/recent_posts") => "/tmp/cache/localhost:3000/blog/recent_posts.cache" 

cache ("turkey") => "/tmp/cache/turkey.cache"
cache (:controller => 'blog', :action => 'show', :id => 1) => "/tmp/cache/localhost:3000/blog/show/1.cache"
cache ("blog/recent_posts") => "/tmp/cache/blog/recent_posts.cache"
cache ("#{request.host_with_port}/blog/recent_posts") => "/tmp/cache/localhost:3000/blog/recent_posts.cache"


清除Fragment Cache的例子:
Java 代码

   1. expire_fragment(:controller => 'blog', :action => 'list', :page => 1) 
   2. expire_fragment(%r{blog/list.*}) 

expire_fragment(:controller => 'blog', :action => 'list', :page => 1)
expire_fragment(%r{blog/list.*})



四、ActiveRecord Cache
Rails Edge中ActiveRecord已经默认使用SQl Query Cache,对于同一action里面同一sql语句的数据库操作会使用cache

五、memcached
越来越多的大型站点使用memcached做缓存来加快访问速度
memcached是一个轻量的服务器进程,通过分配指定数量的内存来作为对象快速访问的cache
memcached就是一个巨大的Hash表,我们可以存取和删除key和value:
Java 代码

   1. @tags = Tag.find :all 
   2. Cache.put 'all_your_tags', @tags 
   3. Cache.put 'favorite_skateboarder', 'Tom Penny' 
   4. skateboarder = Cache.get 'favorite_skateboarder' 
   5. Cache.delete 'all_your_tags' 

@tags = Tag.find :all
Cache.put 'all_your_tags', @tags
Cache.put 'favorite_skateboarder', 'Tom Penny'
skateboarder = Cache.get 'favorite_skateboarder'
Cache.delete 'all_your_tags'


我们可以使用memcached做如下事情:
1,自动缓存数据库的一行作为一个ActiveRecord对象
2,缓存render_to_string的结果
3,手动存储复杂的数据库查询作为缓存
cached_model让我们轻松的缓存ActiveRecord对象,memcahed-client包含在cached_model的安装里,memcahed-client提供了缓存的delete方法
Java 代码

   1. sudo gem install cached_model 

sudo gem install cached_model


我们在config/environment.rb里添加如下代码来使用memcached:
Java 代码

   1. require 'cached_model' 
   2.  
   3. memcache_options = { 
   4.   :c_threshold => 10_000, 
   5.   :compression => true, 
   6.   :debug => false, 
   7.   :namespace => 'my_rails_app', 
   8.   :readonly => false, 
   9.   :urlencode => false 
  10. } 
  11.  
  12. CACHE = MemCache.new memcache_options 
  13. CACHE.servers = 'localhost:11211' 

require 'cached_model'

memcache_options = {
  :c_threshold => 10_000,
  :compression => true,
  :debug => false,
  :namespace => 'my_rails_app',
  :readonly => false,
  :urlencode => false
}

CACHE = MemCache.new memcache_options
CACHE.servers = 'localhost:11211'


对于production环境我们把上面的代码挪到config/environments/production.rb里即可
然后让我们的domain model集成CachedModel而不是ActiveRecord::Base
Java 代码

   1. class Foo < CachedModel 
   2. end 

class Foo < CachedModel
end


然后我们就可以使用memcached了:
Java 代码

   1. all_foo = Foo.find :all 
   2. Cache.put 'Foo:all', all_foo 
   3. Cache.get 'Foo:all' 

all_foo = Foo.find :all
Cache.put 'Foo:all', all_foo
Cache.get 'Foo:all'


需要注意的几点:
1,如果你查询的item不在缓存里,Cache.get将返回nil,可以利用这点来判断是否需要重新获取数据并重新插入到缓存
2,CachedModel的记录默认15分钟后expire,可以通过设置CachedModel.ttl来修改expiration time
3,手动插入的对象也会过期,Cache.put('foo', 'bar', 60)将在60秒后过期
4,如果分配的内存用尽,则older items将被删除
5,可以对每个app server启动一个memcached实例,分配128MB的内存对一般的程序来说足够

注:本文参考Ruby on Rails Caching Tutorial和memcached Basics for Rails两篇网文
BTW:Rails Envy上面有几个Ruby On Rails的广告视频,是关于与PHP/Java的比较,比较生动搞笑
分享到:
评论

相关推荐

    Rails Cache

    **Rails Cache 深度解析** Rails Cache 是 Ruby on Rails 框架中的一个核心特性,用于提升Web应用的性能,通过缓存数据减少数据库查询,从而加快页面加载速度。在高并发环境下,缓存机制显得尤为重要,因为它能显著...

    Rails缓存架构设计

    - **基于Rails Cache的封装**:尽管简单,但能有效地实现对象缓存的自动化管理,适用于简单的场景。 #### 七、总结 构建高性能Web应用的缓存架构是一个系统工程,涉及到多个层面的技术选择和实现细节。通过对上述...

    second_level_cache:受CacheMoney和cache_fu启发的直写和直读缓存库,支持ActiveRecord 4、5和6

    SecondLevelCache是​​一个受Cache Money和cache_fu启发的直写式和直读式缓存库,支持ActiveRecord 4,ActiveRecord 5和ActiveRecord 6。 直读:按ID进行的查询,例如current_user.articles.find(params[:id]) ,...

    Advanced Rails

    书中会介绍如何通过缓存(如Action Cache和Page Cache)、数据库查询优化、资产管道优化等手段提升应用性能。 2. **复杂的路由**:Rails的路由系统允许灵活地定义资源和URL结构。高级Rails会讲解如何创建更复杂的...

    rails-cache-inspector:用于片段缓存的可视化调试的简单工具

    安装将此行添加到应用程序的Gemfile中: gem 'rails-cache-inspector' , group : :development用法配置突出显示 # config/initializers/rails_cache_inspector.rbRailsCacheInspector . configuration . highlight_...

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

    Cache Complex Queries Using Materialized Views Chapter 11. Asynchronously Load Data from Many Sources Chapter 12. Wrangle Forms and Validations with Angular Chapter 13. Dig Deeper Appendix A1. Full ...

    rails-cache-extended:帮助程序和日志记录添加到 Rails 缓存

    Rails::Cache::Extended 这允许为记录集合生成自动过期的缓存键 安装 将此行添加到应用程序的 Gemfile 中: gem 'rails-cache-extended' 然后执行: $ bundle 或者自己安装: $ gem install rails-cache-...

    rails性能优化

    在使用Rails基准测试器时,可以指定不同的选项来进行性能测试,例如通过-perf选项来启用或覆盖默认的日志记录级别,通过-nocache选项关闭Rails缓存以排除缓存对测试结果的影响,以及通过-path选项来指定测试脚本的...

    Ruby-Rails实战之B2C商城开发

    10. 性能优化:使用缓存(如Rails的Page Cache、Action Cache)、数据库索引、资产打包(如Webpacker或Sprockets)等技术提高网站性能。 在这个项目中,文件夹`master_rails_by_actions-master`可能包含了整个商城...

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

    然后在控制器中使用 `cache_page` 方法来缓存特定的动作响应,如 `cache_page @post`。 2. **页面缓存的局限性**:不是所有页面都适合使用页面缓存。如果页面内容根据用户身份或行为动态变化,例如登录状态、个人...

    Ruby on Rails 的 Redis 存储.zip

    Ruby on Rails 的 Redis 存储redis-rails为Ruby on Rails提供全套存储(Cache、Session、HTTP Cache)。请参阅redis-store 主自述文件以了解一般准则。关于 Rails 5.2 的简要说明Rails 5.2.0包含一个开箱即用的 ...

    Complex Rails system_Rails_优化_

    3. **数据缓存**:使用低级缓存`Rails.cache`存储查询结果,避免重复计算。 三、代码优化 1. **避免在循环中进行数据库查询**:将查询移到循环之外,减少不必要的数据库交互。 2. **减少视图复杂性**:保持视图...

    Rails Best Practices

    12. **缓存**:利用Rails的缓存机制,如Action Cache、Fragment Cache和低级别的Redis或Memcached,减少数据库查询,提高响应速度。 13. **部署与持续集成(CI/CD)**:使用Heroku、Capistrano等工具进行部署,配合...

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

    然而,Rails 4.0中引入了Page Cache和Fragment Cache作为替代方案,这是因为Action Cache在某些情况下可能会导致复杂的缓存管理和失效问题。Page Cache(也称为Action Controller Caching)将整个页面的HTML直接缓存...

    model_cache:用于缓存模型代码的 Rails 插件

    模型缓存ModelCache 是一个简单的 Rails 缓存插件,使用memcached 。 它为您的模型提供缓存功能,允许: 基于通用键(ActiveRecord cache_key在幕后添加)在模型实例方法中缓存代码块缓存您的实例方法,可选择使用...

    rails web server deploy guide

    9. **性能优化**:通过缓存策略(如Action Cache和Page Cache)、负载均衡和预热等方式提升Rails应用的性能。 10. **日志和监控**:配置日志管理和监控工具(如Lograge和New Relic),以便追踪应用性能和错误。 11...

    Rails 4 Application Development.pdf

    - **性能优化**:提高了数据库查询性能,并引入了ActiveRecord Query Cache来缓存查询结果。 - **简化代码**:去除了许多不再使用的功能,使代码更加简洁。 #### 二、Rails 4开发环境搭建 - **安装Ruby**:推荐...

Global site tag (gtag.js) - Google Analytics