3. GoRuCo | 6/21/2014 | @ehm_may
Overview
• Caching
• Content Delivery Networks (CDNs)
• Modern Innovations in CDNs (dynamic edge caching)
• Dynamic edge caching with Ruby/Rails
4. GoRuCo | 6/21/2014 | @ehm_may
Caching Foundations
• I have data stored somewhere (HDD, DB, Cloud)
• I access that data often
• Move data closer to where I am
• Move data to faster storage !
• Side effect: Reduce load on original storage location
16. GoRuCo | 6/21/2014 | @ehm_may
LRU Interface
• set(object) - O(1) - stores object, calls prune( ) (if cache is full)
• get(key) - O(1) - returns object, moves it to the “head” of the cache
17. GoRuCo | 6/21/2014 | @ehm_may
LRU Interface
• set(object) - O(1) - stores object, calls prune( ) (if cache is full)
• get(key) - O(1) - returns object, moves it to the “head” of the cache
• prune( ) - removes object from “tail” of the cache
18. GoRuCo | 6/21/2014 | @ehm_may
LRU Implementation
• HashTable to store data - get( ) and set( ) functions
• Doubly Linked List for tracking “time since last use”
32. GoRuCo | 6/21/2014 | @ehm_may
Edge caching static content is easy!
The Asset Pipeline builds links with the asset_host
!
Rails:
# config/environments/production.rb
config.action_controller.asset_host = “mycdn.coolcdn.com”
!
Sinatra: (with something like sinatra_asset_pipeline)
# in app.rb
set :assets_host, ‘mycdn.coolcdn.com’
33. GoRuCo | 6/21/2014 | @ehm_may
Cache invalidation is hard.
Especially when your cache is
globally distributed
34. GoRuCo | 6/21/2014 | @ehm_may
Content Delivery Networks
• How data/requests get to the edge
• Controlling content with HTTP Headers
• Lesser known CDN features
37. GoRuCo | 6/21/2014 | @ehm_may
PUSH CDN
• You “push” content to the CDN
• Usually happens when an asset is updated
• Harder to keep assets in sync
• Can strain origin server when pushing
38. GoRuCo | 6/21/2014 | @ehm_may
PULL CDN
• CDN “pulls” content from your origin server
• Seamless updates when assets change
• Small latency cost on first request
• Acts as a reverse proxy
43. GoRuCo | 6/21/2014 | @ehm_may
Request Routing
• Request made by client
• Request triggers DNS lookup
44. GoRuCo | 6/21/2014 | @ehm_may
Request Routing
• Request made by client
• Request triggers DNS lookup
• DNS resolves request to a geographical region
45. GoRuCo | 6/21/2014 | @ehm_may
Request Routing
• Request made by client
• Request triggers DNS lookup
• DNS resolves request to a geographical region
• Request forwarded to CDN Edge nearest to that region
46. GoRuCo | 6/21/2014 | @ehm_may
Controlling content on your
Content Delivery Network
Using HTTP Headers
48. GoRuCo | 6/21/2014 | @ehm_may
Cache-Control
• Specify behavior intended to prevent caches from interfering with
the request or response
• Override the default caching algorithm
• Specify what can be cached
• Specify how long to cache
50. GoRuCo | 6/21/2014 | @ehm_may
Cache-Control: max-age!
!
Indicates how long to keep response
fresh. Respected by all shared caches
(CDN) and private caches (browser).
51. GoRuCo | 6/21/2014 | @ehm_may
Use Cache-Control: max-age as an
umbrella strategy to cache
responses
64. GoRuCo | 6/21/2014 | @ehm_may
Sneaky Example
• Surrogate-Control takes priority over Cache-Control
• Surrogate will cache for 1 year
• Browser will cache for 30 minutes
• Sometimes Surrogate-Control is stripped by the Surrogate
71. GoRuCo | 6/21/2014 | @ehm_may
HTTP Keep-Alive Header
• Connection: Keep-Alive
• TCP Session is kept open for an extended period
• Eliminate costly TCP Handshake
• In CDN Land edge nodes may keep connections alive with origin =>
faster cache misses (Dynamic Site Acceleration)
74. GoRuCo | 6/21/2014 | @ehm_may
Instant Purging
• PURGE request comes in to edge node
• Edge node purges and passes to on to nearest neighbors
• Recurse until everyone has purged
brucespang.com/bimodal
75. GoRuCo | 6/21/2014 | @ehm_may
Instant Purging
• Purges happen globally in < 300ms on 95th percentile
• Enables dynamic content caching at the edge
brucespang.com/bimodal
www.fastly.com/blog/building-fast-and-reliable-purging-system
76. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Caching
• Explain process
• Example using Rails Fragment caching
• Map fragment caching to edge caching
78. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Content
• Data that changes frequently
79. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Content
• Data that changes frequently
• Frequently does not mean continuously
80. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Content
• Data that changes frequently
• Frequently does not mean continuously
• Periods of time where data is not being changed
81. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Caching is when you
cache data in-between regeneration
82. GoRuCo | 6/21/2014 | @ehm_may
Beneficial when dynamic data is
requested multiple times
84. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Caching - How To
1. Create unique cache keys
85. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Caching - How To
1. Create unique cache keys
2. Bind data to cache keys
86. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Caching - How To
1. Create unique cache keys
2. Bind data to cache keys
3. Purge with cache key on data updates
96. GoRuCo | 6/21/2014 | @ehm_may
1. Create unique cache keys
In CDN land, Surrogate-Keys are
your cache keys
97. GoRuCo | 6/21/2014 | @ehm_may
1. Create unique cache keys
Surrogate-Key is a HTTP
Header that tells the cache to
associate key(s) with response
data
98. GoRuCo | 6/21/2014 | @ehm_may
2. Bind data to cache keys
Use Surrogate-Key on HTTP GETs
GET /product/123
!
HTTP/1.1 200 OK
Content-Type: text/json
Surrogate-Control: max-age=86400
Surrogate-Key: products product/123
{id: 123, name: “Kewl Keyboard”, price: “$124.99”}
99. GoRuCo | 6/21/2014 | @ehm_may
3. Purge with cache key on data updates
PURGE Surrogate-Key on !
HTTP POST, PUT, DELETE
PUT /product/123
{price: “$1.00”}
!
# In PUT request handler
PURGE /product/123
100. GoRuCo | 6/21/2014 | @ehm_may
Implementing edge caching in
Ruby on Rails
101. GoRuCo | 6/21/2014 | @ehm_may
fastly-rails!
github.com/fastly/fastly-rails
!
Contains helpers for integrating with
dynamic edge caching
102. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Edge Caching on Rails
1. Extend models with surrogate key instance methods
103. GoRuCo | 6/21/2014 | @ehm_may
class Product < ActiveRecord::Base
!
def resource_key
“#{table_key}/#{id}" # e.g. “products/1234”
end
!
def table_key
self.class.table_name # e.g. “products”
end
end
104. GoRuCo | 6/21/2014 | @ehm_may
Dynamic Edge Caching on Rails
1. Extend models with surrogate key instance methods
2. Add ActionController helpers to set up headers
105. GoRuCo | 6/21/2014 | @ehm_may
class ProductsController < ApplicationController
before_filter :set_cache_control_headers, only: [:index, :show]
!
def index
@products = Product.all
set_surrogate_key_header @product.table_key
respond_with @products
end
!
def show
@product = Products.find(params[:id])
set_surrogate_key_header @product.record_key
respond_with @product
end
end
106. GoRuCo | 6/21/2014 | @ehm_may
class ProductsController < ApplicationController
before_filter :set_cache_control_headers, only: [:index, :show]!
!
def index
@products = Product.all
set_surrogate_key_header @product.table_key
respond_with @products
end
!
def show
@product = Products.find(params[:id])
set_surrogate_key_header @product.record_key
respond_with @product
end
end