Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A caching pie

A caching pie

"Peeling off the cache layers of a Ruby on Rails application"

This is an internal talk I gave to the Codegram team. It's a brief exploration of most of the mechanism and strategies the Rails stack gives us.

Josep Jaume Rey

September 27, 2013
Tweet

Other Decks in Programming

Transcript

  1. A Caching Pie Peeling off the cache layers of a

    Ruby on Rails application Friday, September 27, 13
  2. A fast temporary storage where recently or frequently used information

    is stored to avoid having to reload it from a slower storage medium. Friday, September 27, 13
  3. •OMG so simple •Any kind of ruby object •Low impact,

    no dependencies What’s good Friday, September 27, 13
  4. •Standalone network service •Simple API (get, set, delete) •Uber fast

    key-value store What the heck is it? Friday, September 27, 13
  5. •Standalone network service •Simple API (get, set, delete) •Uber fast

    key-value store •Persistent storage What the heck is it? Friday, September 27, 13
  6. •Standalone network service •Simple API (get, set, delete) •Uber fast

    key-value store •Persistent storage •LRU expiration (maximum size) What the heck is it? Friday, September 27, 13
  7. •Standalone network service •Simple API (get, set, delete) •Uber fast

    key-value store •Persistent storage •LRU expiration (maximum size) •Open source, mature & stable What the heck is it? Friday, September 27, 13
  8. 1 require 'dalli' 2 dalli = Dalli::Client.new 3 4 def

    ed 5 return balls if balls = dalli.get('ed') 6 7 balls = Balls.new 8 dalli.set('ed', balls) 9 10 balls 11 end Friday, September 27, 13
  9. 1 # With Rails 2 # 3 def ed 4

    Rails.cache.fetch 'ed' do 5 Balls.new 6 end 7 end Friday, September 27, 13
  10. 1 # Parameters 2 # 3 def ed(color = 'red')

    4 Rails.cache.fetch "ed-#{color}" do 5 Balls.new(color) 6 end 7 end Friday, September 27, 13
  11. 1 # Expiration 2 # 3 def ed 4 Rails.cache.fetch

    "ed", expires_in: 1.hour do 5 Balls.new 6 end 7 end Friday, September 27, 13
  12. Rails: Other implementations • ActiveSupport::Cache::Store (abstract) • ActiveSupport::Cache::MemoryStore • ActiveSupport::Cache::FileStore

    • ActiveSupport::Cache::NullStore • ActiveSupport::Cache::RedisStore Friday, September 27, 13
  13. Rails: Other implementations • ActiveSupport::Cache::Store (abstract) • ActiveSupport::Cache::MemoryStore • ActiveSupport::Cache::FileStore

    • ActiveSupport::Cache::NullStore • ActiveSupport::Cache::RedisStore • ActiveSupport::Cache::CouchbaseStore Friday, September 27, 13
  14. 1 class StuffController < ActionController::Base 2 def show 3 thing

    = Thing.find(params[:id]) 4 5 render json: thing.to_json 6 end 7 end Friday, September 27, 13
  15. 1 class StuffController < ActionController::Base 2 def show 3 thing

    = Thing.find(params[:id]) 4 json = Rails.cache.fetch(thing){ thing.to_json } 5 6 render json: json 7 end 8 end Friday, September 27, 13
  16. 1 # Only with Rails 2 thing.cache_key 3 => "thing/1-20130919103345"

    class ID updated_at Friday, September 27, 13
  17. 1 # app/views/stuff/show.json.erb 2 <%= cache @thing do %> 3

    { 4 thing: <%= render partial: 'thing', object: @thing %> 5 } 6 <%= end %> Friday, September 27, 13
  18. 1 # app/views/stuff/show.json.erb 2 <%= cache @thing do %> 3

    { 4 thing: <%= render partial: 'thing', object: @thing %> 5 } 6 <%= end %> Problem: What if the template changes? Friday, September 27, 13
  19. •Beware of time-sensitive cached data •Partial support of templating engines

    •`updated_at` touching can lead to rabbit holes Be careful! Friday, September 27, 13
  20. 1 # HTTP Expiration caching 2 # 3 class StuffController

    < ActionController::Base 4 def show 5 @thing = Thing.find(params[:id]) 6 expires_in 2.hours, public: true 7 end 8 end Friday, September 27, 13
  21. 1 # HTTP Expiration caching 2 # 3 class StuffController

    < ActionController::Base 4 def show 5 @thing = Thing.find(params[:id]) 6 expires_in 2.hours, public: true 7 end 8 end HTTP/1.1 200 OK Cache-Control: max-age=3600, public Friday, September 27, 13
  22. 1 # HTTP Validation caching 2 # 3 class StuffController

    < ActionController::Base 4 def show 5 @thing = Thing.find(params[:id]) 6 7 fresh_when( 8 last_modified: @thing.updated_at.utc, 9 etag: Digest::MD5.hexdigest(@thing.cache_key) 10 ) 11 end 12 end Friday, September 27, 13
  23. 1 # HTTP Validation caching 2 # 3 class StuffController

    < ActionController::Base 4 def show 5 @thing = Thing.find(params[:id]) 6 7 fresh_when( 8 last_modified: @thing.updated_at.utc, 9 etag: Digest::MD5.hexdigest(@thing.cache_key) 10 ) 11 end 12 end HTTP/1.1 200 OK Last-Modified: Sat Sep 21 11:09:56 UTC 2013 ETag: "686897696a7c876b7e" Friday, September 27, 13
  24. •Will send if-modified-since and etag to each request •Can combine

    expiration caching and validation caching: http://stackoverflow.com/a/6351738/871401 The browser knows its stuff Friday, September 27, 13
  25. •Will send if-modified-since and etag to each request •Can combine

    expiration caching and validation caching: http://stackoverflow.com/a/6351738/871401 •Will use the previously stored document when 302 is returned The browser knows its stuff Friday, September 27, 13
  26. •Rails can skip rendering (and return 302) •Saves bandwith •Pure

    HTTP semantics What’s good Friday, September 27, 13
  27. •Expiration-caching responses won’t be shared across clients •HTTP caching is

    hard: http://tools.ietf.org/html/ rfc2616#section-13 Caveats Friday, September 27, 13
  28. •Comes with the Rails stack •Watches HTTP cache headers and

    stores them config.middleware.use Rack::Cache Friday, September 27, 13
  29. •Comes with the Rails stack •Watches HTTP cache headers and

    stores them •Will return cached response to prevent app to be hit config.middleware.use Rack::Cache Friday, September 27, 13
  30. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached Friday, September 27, 13
  31. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached •Entire views are cached Friday, September 27, 13
  32. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached •Entire views are cached •Layers and layers of partials are cached Friday, September 27, 13
  33. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached •Entire views are cached •Layers and layers of partials are cached •Decorator methods are cached Friday, September 27, 13
  34. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached •Entire views are cached •Layers and layers of partials are cached •Decorator methods are cached •Assets are cached Friday, September 27, 13
  35. In a typical Rails app... •Method calls are cached ||=

    •Database queries are cached •Entire views are cached •Layers and layers of partials are cached •Decorator methods are cached •Assets are cached •External API calls are cached Friday, September 27, 13
  36. Yo’mama’s arse is cached ...cause it’s so big it takes

    too much request time LOL Friday, September 27, 13
  37. There are only two hard things in Computer Science: cache

    invalidation and naming things. Phil Karlton (Netscape) Friday, September 27, 13