今天插一脚,介绍一下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 博文链接:https://mmm.iteye.com/blog/134696
SecondLevelCache是一个受Cache Money和cache_fu启发的直写式和直读式缓存库,支持ActiveRecord 4,ActiveRecord 5和ActiveRecord 6。 直读:按ID进行的查询,例如current_user.articles.find(params[:id]) ,...
安装将此行添加到应用程序的Gemfile中: gem 'rails-cache-inspector' , group : :development用法配置突出显示 # config/initializers/rails_cache_inspector.rbRailsCacheInspector . configuration . highlight_...
Rails::Cache::Extended 这允许为记录集合生成自动过期的缓存键 安装 将此行添加到应用程序的 Gemfile 中: gem 'rails-cache-extended' 然后执行: $ bundle 或者自己安装: $ gem install rails-cache-...
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 ...
模型缓存ModelCache 是一个简单的 Rails 缓存插件,使用memcached 。 它为您的模型提供缓存功能,允许: 基于通用键(ActiveRecord cache_key在幕后添加)在模型实例方法中缓存代码块缓存您的实例方法,可选择使用...
Ruby on Rails的Redis商店 redis-rails为Ruby on Rails提供了一整套存储(缓存,会话, HTTP缓存)。 有关一般准则,请参见主要的。 关于Rails 5.2的快速说明 ... cache_store = :redis_store , "re
Rails的ActiveRecord自身没有带强大的对象缓存功能,这是AR的一个重大的遗憾。早在2008年开始,我们就借鉴了Java强大的ORM 框架Hibernate的二级对象缓存编写了这个Rails的AR对象缓存插件,并且一直作为JavaEye网站...
只需编写常规的Rails代码,即可在Rails中创建微服务。 该宝石提供: 透明的API密钥身份验证。 基于标头的路由器级API版本。 通过验收测试记录微服务端点的方法。 结构化错误,可以从无效的Active Record,异常...
EasyCaptcha 基于rmagick的rails 3的简单验证码实现 经过Rails 3.2.8的测试 安装 添加到Gemfile gem 'easy_captcha' ... # Cache temp dir from Rails.root # config.cache_temp_dir = Rails.root
包括has_cache在Rails项目Gemfile : gem 'has_cache' 在类中调用has_cache ,例如在模型中: class User < ActiveRecord :: Base has_many :posts , inverse_of : :user has_cache end class Post < ...
Record Cache - 在Rails 3中缓存Active Model Records
此外,在Ruby on Rails上使用它也是非常的简单。 如何使用: 对于在Rails上使用Redis Store,首先我们需要在Gemfile文件中添加入口 gem 'redis-rails' gem 'redis-rack-cache' # optional 然后我们就会有...
join_cache 使用Rails缓存可以更快地进行ActiveRecord关联。 什么? 假设您搭建了Rails应用并最终得到了以下结果: class Employee < ActiveRecord xss=removed> Team Load SELECT "teams" . * FROM "teams" ...
反文化 Turbo为您的Rails应用程序提供计数器缓存。 对Rails标准计数器缓存的巨大改进...product.categories_count # => will use counter cache without query 安装 将counter_culture添加到您的Gemfile中: gem 'co
缓存管理器可安装的Rails引擎可查看您的缓存并管理密钥/清理缓存。 注意:当前已通过文件存储和Redis缓存存储进行测试。安装在您的Gemfile中添加宝石 gem 'cache_manager' 和捆绑$ bundle install 安装后,将引擎...
确保在config / environment / test.rb文件中关闭了Rails的cache_classes : Rails . application . configure do # turn off this! config . cache_classes = false end 3)启动控制台 使用Rails,使用rails c ...
“This Rails Application Is the Only Application on Earth” 43 Sit Atop the Shoulders of Giants 43 Choosing the Right RDBMS 44 A Note on Migrations 44 Dispelling Myths 46 Operations and Reporting 47 5...