Post on 06-May-2015
description
Caching With Rails
By Carmen Diaz Echauri – cdechauri@gmail.com For www.blazingcloud.net
Rails version 2.3.8
Caching with Rails
Scaling your Applica
Fons
• Rails provides by default three techniques: – Page Caching – AcFon Caching – Fragment Caching
Page Caching
• Allows the request for a generated page to be fulfilled by the webserver, without ever having to go through your Rails applicaFon.
Client Apache Mongrel
Public/users.html
hOp://localhost:3000/users
Page Caching
Next Fme we request the same page, apache will load the page from the filesystem and send it back to the client.
Client Apache Mongrel
Public/users.html hOp://localhost:3000/users
When we might want to page cached?
• When every user always sees exactly the same content on a page, even if they are login to the admin interface or not. But It's always the same.
• It doesn't change so oWen. Maybe once per day, week or month.
Get started with caching….
• Make sure config.acFon_controller.perform_caching is set to true for your environment. (config/environments/development.rb)
config.acFon_controller.perform_caching = true
Page Caching
Page Caching OpFons
• format.json {render :json => @users}
• format.iphone – /config/iniFalizers/mime_types.rb
• Mime::Type.register_alias “text/html”, :iphone – /app/views/users/index.iphone.erb
/public/users.html /public/users.xml /public/users.json /public/users.iphone
Caching locaFon /config/environment.rb
versus
Page caching
• Page caching ignores all parameters – hOp://localhost:3000/users?page=1 Will be wriOen out
so if someone request hOp://localhost:3000/users?page=3 it will be gegng users.html.
AcFon Caching
• Caching stored – Page Caching
• Stored on Disk – AcFon & Fragment Caching
• Use the configured cache that we configure in our rails instance.
When to do AcFon Caching? • When we need filters to run – Like authenFcaFon
Client Apache Mongrel
Public/posts.html
hOp://localhost:3000/posts
Run Filters (authenFcate)
AcFon Caching
AcFon Caching
Didn’t call the acFon. It loaded straight out of the cache
It executed the acFon
AcFon Caching OpFons
/config/environments/development.rb
• config.cache_store = :file_store, 'tmp/cache’
(AcFveSupport::Cache::FileStore)
• config.cache_store = :memory_store
(AcFveSupport::Cache::MemoryStore)
– {} in memory –background-‐. But you can run out of memory – No sharing between processes. You cannot use it if you run more than
one instance of your rails apps.
AcFon Caching OpFons….
• config.cache_store = :mem_cache_store
• config.cache_store = :mem_cache_store, :namespace => “store” (share apps)
• config.cache_store = :mem_cache_store, 192.168.1.255:1001, 192.168.1.255:1002 (mulFple servers)
(AcFveSupport::Cache::MemCacheStore) • config.cache_store = :drb_store
(AcFveSupport::Cache::DRbStore) • config.cache_store = :custom_store
AcFon Caching • Features
– Cached the acFon without the layout.
it will only cache your acFon content. So, if you need some sort of data you might want to use before_filter and set you instance variable
AcFon Caching
• Features (cont) • CondiFonal AcFon acFon using :if (or :unless) => Proc.new{….} to
specify when the acFon should be cached.
• Specific path using :cache_path => Proc.new { |controller| or :cache_path => <method>
:expires_in =>1.hour to specify when the acFon should be cached.
(only with memcached & rails > 2.1)
Fragment Caching • Is useful for dynamic web applicaFons • Allows you to fragment many pieces of the view. The pieces will be wrapped in a cache block and served out of the cache store when the next request comes in.
Client Apache Mongrel
header
hOp://localhost:3000/users body
widgets
Fragment Caching To implement fragment caching, you cache your method in the view.
All keys are prefixed with "views/"
Fragment Caching
You can create your own key: <% cache("#{@user.id}-‐recents_joined") do %> or use the rails way
<% cache([user, post, “toolbar”]) do %>
Memcached
• Is a hash in memory, key-‐value store {} in memory
(LiveJournal) – To implement /config/environments/producFon.rb
config.cache_store = :mem_cache_store Same thing as config.cache_store = :memory_store
but it runs as a separate process. You can have several rails
instances that references the same mencached instance -‐ Note: make sure to install the gem memcached-‐client.
Memcached uses • Fragment Cache Store
• AcFon & Fragment Caching
Memcached uses
• As an Object Store – Rails.cache.read – Rails.cache.write – Rails.cache.fetch – Rails.cache.delete – Rails.cache.exists? – Rails.cache.clear – Rails.cache.increment – Rails.cache.clear
Memcached uses
Memcached …. Some points: -‐ Expire at def self.recent Rails.cache.fetch("recent_posts", :expires_in => 30.minutes) do self.find(:all, :limit => 10) end
end Run this query every 30 minutes…
-‐ You don’t need to have memcached installed to develop locally You will get MemCacheError (No connecFon to server): No connecFon to server Cache miss: But, your app will work just fine. Rails will always execute the contents of the fetch blocks, and will return nil for any reads.
Expiring cached pages One’s first inclinaFon may be to expire pages in the Controller and usually via the update method. Depending on which technique you choose to expire pages you can use the method expire_page {acFon,fragment}
Instead of having expire methods around your controllers, to clear cache files based on when a model is updated, sweepers are the way to go.
Expiring cached page AcFonController::Caching::Sweeper class. (Share Objects)
– Can observe Controllers – Can observe Models
Hooks: Any observer callbacks
aWer create
aWer destroy aWer_save, etc.
Also in any controllers callbacks • before/aWer_<controller_name>
• before/aWer_<controller_name>_<acFon>
Expiring cached page To implement sweepers:
Declare a new load path in /config/environment.rb to keep the sweepers separate from models and controllers.
config.load_paths << "#{RAILS_ROOT}/app/sweepers”
Create the folder and the observer files
Expiring cached page
And then we will tell the controller to use the sweeper
cache_sweeper :user_sweeper, :only => [:create, :update, :destroy]
When to call the method
Observe the model
Expiring cached page
Another way to expire. Clearing the cache
And you could use it in a cron call…
Some thoughts ImplemenFng page caching can be easy. However, expiring can be prove to be a bit more challenging .
• I find tesFng kind of tricky. • I read through numerous blog posts but I couldn’t quite figure out
how to get things to work as I hoped. • The following are alternaFves I’ve recently used:
– Custom Macthers by overwriFng the matches? method • AcFonController::Caching::AcFons
– Build your CachePage / Fragment Page class and use • AcFonController::Base.expire_page( ) • AcFonController::Caching::Fragments
– expire_fragment – fragment_cache_key – fragment_exist? – read_fragment – write_fragment