Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

2

Share

Download to read offline

Rails Caching Secrets from the Edge

Download to read offline

When it comes to caching, there are two types of web developers - those with phat stacks of cache money and those suffering from cache anxiety. Caching is particularly handy when scaling Rails apps, however we often avoid putting in effort because it can quickly get complicated without effective strategies. Rails provides a host of built-in caching interfaces that are easy to leverage and extend. I’ll talk about how to do this and combine rails with technologies like CDNs and HTTP accelerators like Varnish so that you can more effectively cache everything, everywhere without fear of serving stale content.

Michael May is an API Engineer at Fastly and a former Austinite, now hailing from San Francisco. While in Texas he studied at UT Austin and co-founded CDN Sumo, which was acquired by Fastly. He’s waiting for the day when FaaS (Franklin BBQ as a Service) becomes a thing and dreams about fast websites.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Rails Caching Secrets from the Edge

  1. 1. Rails Caching Secrets: From the Edge! Michael May | @ohaimmay | austinonrails | 10/28/2014
  2. 2. We’re Hiring! Distributed Systems! Ruby C Go Perl JS
  3. 3. We are here • Rails caching best practices • Dynamic content • Edge caching / Content Delivery Networks • Edge caching dynamic content with Rails
  4. 4. Rails caching • Query/SQL • Page/Action (removed from Rails 4 core!) • Asset • Fragment
  5. 5. Rails caching config.action_controller.perform_caching = true
  6. 6. Query caching • Automagically done by rails when perform_caching = true • Not cached between requests! • Could just store the query result in a variable
  7. 7. Custom Query Caching class Product < MyActiveModel def self.latest Rails.cache.fetch("latest", expires_in: 8.hours) do Product.last(50) end end end
  8. 8. Asset Pipeline • Serve static assets from nginx or apache • config.serve_static_assets = false • Enable Compression* • config.assets.compress = true • # Rails 4 config.assets.css_compressor = :yui config.assets.js_compressor = :uglifier • Asset Digests • config.assets.digest = true
  9. 9. Enable Compression* Compress all responses with gzip, deflate, etc. # in application.rb module FastestAppEver class Application < Rails::Application config.middleware.use Rack::Deflater end end * http://robots.thoughtbot.com/content-compression-with-rack-deflater
  10. 10. $ curl -sv -H “Accept-Encoding: deflate” http://fast.mmay.rocks/catz.json * Connected to fast.mmay.rocks (127.0.0.1) port 666 > GET /catz.json HTTP/1.1 > User-Agent: curl > Host: fast.mmay.rocks:666 > Accept-Encoding: deflate,gzip > < HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 < Vary: Accept-Encoding < Content-Encoding: deflate < Cache-Control: max-age=60, s-maxage=3600 < Transfer-Encoding: chunked < * magical encoded bytes* V*.I,)-VRJ-*RN@ ɥEEy%9
  11. 11. Before After
  12. 12. Asset Caching • Configure an asset host if needed • config.action_controller.asset_host = ENV[‘FASTLY_CDN_URL'] • Cache-Control like a pro • config.static_cache_control = 'public, s-maxage=15552000, maxage=2592000'
  13. 13. HTTP Headers RFC 2616 Section 14
  14. 14. Cache-Control HTTP Header “public, maxage=2592000, s-maxage=15552000” public “please cache me” maxage=2592000 “keep me for 30 days” s-maxage=15552000 “PROXIES ONLY! - Keep me for 180 days”
  15. 15. Bonus Cache-Control Directives! • stale-while-revalidate • Serve the cached (stale) content for n seconds while you re-fetche the new content in the background • Cache-Control: maxage=604800, stale-while-revalidate=3600 • “Serve stale for up to an hr while you fetch the latest behind the scenes” • stale-if-error • If the re-fetch fails within n seconds of the content becoming stale, serve the cached content • Cache-Control: max-age=604800, stale-if-error=86400 • “Serve stale for up to an hr if origin responds with 4xx or 5xx”
  16. 16. ETags • Automatically added into requests with Rack::ETag • Rails renders response every time to calculate etag • Override default with Conditional GETs • stale?(@model) • fresh_when(@model)
  17. 17. The Vary HTTP Header • Change response base on the value of another HTTP Header • Example: “Vary: Accept-Encoding” Accept-Encoding: gzip => Serve Response A Accept-Encoding: deflate => Serve Response B • “This response changes for different values of the Accept-Encoding header”
  18. 18. Vary Best Practices • Please do not Vary on User-Agent • There are THOUSANDS of these! • Limits caching benefits - almost Impossible to serve the same response more than once! • In general, avoid varying on anything other than content encoding
  19. 19. Dynamic Content • Changes are unpredictable! • User driven events • Can’t just set a Time To Live (TTL) • Frequently, but not continuously changing • Actually static for short periods of time (we can cache static things)!
  20. 20. Dynamic Content Caching • Usually don’t (╯°□°)╯︵ ┻━┻ • Edge Side Includes (ESI) • Dynamic Site Acceleration (DSA)
  21. 21. Fragment Caching The rails answer to caching dynamic HTML # products/index.html.erb <% cache(cache_key_for_products) do %> <% Product.all.each do |p| %> <%= link_to p.name, product_url(p) %> <% end %> <% end %> # products_controller.rb def update … expire_fragment(cache_key_for_products) … end
  22. 22. Nested Fragment Caching <% cache(cache_key_for_products) do %> All available products: <% Product.all.each do |p| %> <% cache(p) do %> <%= link_to p.name, product_url(p) %> <% end %> <% end %> <% end %>
  23. 23. Nested Fragment • Tedious • Comb through (probably terrible) view code • Cache keys are weird • “A given key should always return the same content.” - Rails • But I like “A given key should always return the most up-to-date content” - like a DB primary key • Hacking around cache limitations • Memcache and wildcard purging
  24. 24. Nested Fragment • Garbage left in the cache • Defaults writing to disk • What about dynamic API caching? • “The caching itself happens in the views based on partials rendering the objects in question” • Take control over your cached data!
  25. 25. Edge Caching with things like CDNs
  26. 26. Edge Caches • Geographically distributed • Highly optimized storage and network (nanoseconds count) • Move content physically closer to end-users • DECREASE LATENCY! (speed of light sux lol)
  27. 27. #cachemoney • Less requests/bandwidth back to your origin server • Avoid complex or less efficient strategies • Edge Side Includes (ESI) • Fragment view caching
  28. 28. Edge caching dynamic content
  29. 29. Our approach to dynamic content • Tag content with Surrogate-Key HTTP headers • Programmatically purge (~150ms globally) • By Surrogate-Key • By resource path • Real-time analytics and log streaming • Optimize the pieces of the network we control
  30. 30. Tagging responses with Surrogate-Keys
  31. 31. class ProductsController < ApplicationController # set Cache-Control, strip Set-Cookie before_filter :set_cache_control_headers,only [:index,:show] def index @products = Product.last(10) # set Surrogate-Key: products set_surrogate_key_header @products.table_key respond_with @products end def show @product = Products.find(params[:id]) # set Surrogate-Key: product/666 set_surrogate_key_header @product.record_key respond_with @product end end
  32. 32. Purge on updates
  33. 33. class ProductsController < ApplicationController def create @product = Product.new(params) if @product.save # purge Surrogate-Key: products @product.purge_all render @product end end ...
  34. 34. def update @product = Product.find(params[:id]) if @product.update(params) # purge Surrogate-Key: product/666 @product.purge render @product end end
  35. 35. fastly-rails github.com/fastly/fastly-rails
  36. 36. Edge caching in practice
  37. 37. Watch out for Set-Cookie! • Nothing with a Set-Cookie header is cached (by default) • Authentication frameworks/middleware might inject Set-Cookie after the rails stack removes it • Avoid caching pains by knowing when, where, and how you use Set-Cookie
  38. 38. Edge scripting with VCL (varnish config lang)
  39. 39. VCL • Fastly VCL Extensions • date/time, geoip, hashing, strings, etc. • Do application logic at the CDN edge
  40. 40. URL Rewriting • Filter bad requests • Normalize or block paths • Apache, nginx • if ($invalid_referer) { return 403; } • You can do this at the edge!
  41. 41. Synthetic Responses
  42. 42. What can we do better? • Add better caching defaults? • Cache-Control, stale-while-revalidate, stale-if-error • Re-use existing rails cache interfaces for edge caching? • ActiveSupport::Cache::EdgeStore • Better integration with HTTP accelerators like Varnish?
  43. 43. Takeaways • Take advantage of Rails built-in caching • Get fancy with Cache-Control directives • Use Google PageSpeed Insights (chrome plugin adds it to dev tools) • Dynamic edge caching is all about the power of purge! • Similar school of thought to rails action caching
  44. 44. Questions? Michael May || @ohaimmay cool links: fastly-rails - github.com/fastly/fastly-rails surrogate keys - fastly.com/blog/surrogate-keys-part-1 cache-control tutorial - docs.fastly.com/guides/tutorials/cache-control-tutorial serve stale cache-control - fastly.com/blog/stale-while-revalidate vary header best practices - fastly.com/blog/best-practices-for-using-the-vary-header caching like & share buttons - fastly.com/blog/caching-like-and-share-buttons pagespeed insights - developers.google.com/speed/pagespeed
  • HirotoshiNakajima

    Dec. 26, 2015
  • amyrlam

    Nov. 19, 2014

When it comes to caching, there are two types of web developers - those with phat stacks of cache money and those suffering from cache anxiety. Caching is particularly handy when scaling Rails apps, however we often avoid putting in effort because it can quickly get complicated without effective strategies. Rails provides a host of built-in caching interfaces that are easy to leverage and extend. I’ll talk about how to do this and combine rails with technologies like CDNs and HTTP accelerators like Varnish so that you can more effectively cache everything, everywhere without fear of serving stale content. Michael May is an API Engineer at Fastly and a former Austinite, now hailing from San Francisco. While in Texas he studied at UT Austin and co-founded CDN Sumo, which was acquired by Fastly. He’s waiting for the day when FaaS (Franklin BBQ as a Service) becomes a thing and dreams about fast websites.

Views

Total views

1,599

On Slideshare

0

From embeds

0

Number of embeds

21

Actions

Downloads

9

Shares

0

Comments

0

Likes

2

×