Rails Caching Secrets from the Edge
-
Upload
michael-may -
Category
Technology
-
view
516 -
download
3
description
Transcript of Rails Caching Secrets from the Edge
![Page 1: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/1.jpg)
Rails Caching Secrets: From the Edge!
Michael May | @ohaimmay | austinonrails | 10/28/2014
![Page 2: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/2.jpg)
We’re Hiring!Distributed Systems! Ruby C Go Perl JS
![Page 3: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/3.jpg)
We are here
• Rails caching best practices
• Dynamic content
• Edge caching / Content Delivery Networks
• Edge caching dynamic content with Rails
![Page 4: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/4.jpg)
Rails caching
• Query/SQL
• Page/Action (removed from Rails 4 core!)
• Asset
• Fragment
![Page 5: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/5.jpg)
config.action_controller.perform_caching = true
Rails caching
![Page 6: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/6.jpg)
Query caching
• Automagically done by rails when perform_caching = true
• Not cached between requests!
• Could just store the query result in a variable
![Page 7: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/7.jpg)
class Product < MyActiveModel
def self.latest Rails.cache.fetch("latest", expires_in: 8.hours) do Product.last(50) end end
end
Custom Query Caching
![Page 8: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/8.jpg)
Asset Pipeline• Serve static assets from nginx or apache
• config.serve_static_assets = false
• Enable Compression*
• config.assets.compress = true
• # Rails 4config.assets.css_compressor = :yuiconfig.assets.js_compressor = :uglifier
• Asset Digests
• config.assets.digest = true
![Page 9: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/9.jpg)
Enable Compression*
* http://robots.thoughtbot.com/content-compression-with-rack-deflater
# in application.rb module FastestAppEver class Application < Rails::Application config.middleware.use Rack::Deflater end end
Compress all responses with gzip, deflate, etc.
![Page 10: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/10.jpg)
$ 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
![Page 11: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/11.jpg)
![Page 12: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/12.jpg)
Before
After
![Page 13: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/13.jpg)
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'
![Page 14: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/14.jpg)
HTTP HeadersRFC 2616 Section 14
![Page 15: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/15.jpg)
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”
![Page 16: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/16.jpg)
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”
![Page 17: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/17.jpg)
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)
![Page 18: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/18.jpg)
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”
![Page 19: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/19.jpg)
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
![Page 20: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/20.jpg)
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)!
![Page 21: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/21.jpg)
Dynamic Content Caching
• Usually don’t (╯°□°)╯︵ ┻━┻
• Edge Side Includes (ESI)
• Dynamic Site Acceleration (DSA)
![Page 22: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/22.jpg)
Fragment CachingThe 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
![Page 23: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/23.jpg)
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 %>
![Page 24: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/24.jpg)
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
![Page 25: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/25.jpg)
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!
![Page 26: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/26.jpg)
Edge Cachingwith things like CDNs
![Page 27: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/27.jpg)
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)
![Page 28: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/28.jpg)
![Page 29: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/29.jpg)
![Page 30: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/30.jpg)
![Page 31: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/31.jpg)
![Page 32: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/32.jpg)
#cachemoney
• Less requests/bandwidth back to your origin server
• Avoid complex or less efficient strategies
• Edge Side Includes (ESI)
• Fragment view caching
![Page 33: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/33.jpg)
Edge caching dynamic content
![Page 34: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/34.jpg)
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
![Page 35: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/35.jpg)
Tagging responses with Surrogate-Keys
![Page 36: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/36.jpg)
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
![Page 37: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/37.jpg)
Purge on updates
![Page 38: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/38.jpg)
class ProductsController < ApplicationController def create @product = Product.new(params) if @product.save # purge Surrogate-Key: products @product.purge_all render @product end end ...
![Page 39: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/39.jpg)
def update @product = Product.find(params[:id]) if @product.update(params) # purge Surrogate-Key: product/666 @product.purge render @product end end
![Page 40: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/40.jpg)
fastly-railsgithub.com/fastly/fastly-rails
![Page 41: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/41.jpg)
Edge caching in practice
![Page 42: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/42.jpg)
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
![Page 43: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/43.jpg)
Edge scripting with VCL(varnish config lang)
![Page 44: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/44.jpg)
VCL
• Fastly VCL Extensions
• date/time, geoip, hashing, strings, etc.
• Do application logic at the CDN edge
![Page 45: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/45.jpg)
URL Rewriting
• Filter bad requests
• Normalize or block paths
• Apache, nginx
• if ($invalid_referer) { return 403; }
• You can do this at the edge!
![Page 46: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/46.jpg)
Synthetic Responses
![Page 47: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/47.jpg)
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?
![Page 48: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/48.jpg)
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
![Page 49: Rails Caching Secrets from the Edge](https://reader033.fdocuments.net/reader033/viewer/2022052908/55945b4d1a28ab190c8b45e8/html5/thumbnails/49.jpg)
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