API Caching with Varnish at
					
					Ruby Usergroup Hamburg 14.10.2015
				
				
					WLW Infrastructure
					
						- Microservices
 
						- 13 Applications/Services
 
						- REST APIs and AMQP
 
						- Each record is owned by one application
 
						- Exception is Elasticsearch
 
						- ~3K internal API requests per minute
 
					
				
				
					Local caching
					
class CompaniesController
  TTL = 10.minutes.freeze
  def show
    @category = Rails.cache.fetch('some_key', expires_in: TTL) do
      api_client.get("companies/#{id}/category")
    end
  end
end
			    
				
				
					Local caching Benefits
					
						- No HTTP request overhead for cached calls
 
					
				
				
					Local caching Drawbacks
					
						- Each app implements it's own cache
 
						- Cached data is duplicated in multiple caches
 
						- Hard to invalidate all caches
 
						- No monitoring e.g. on cache hit rates
 
						- Only simple time based caching
 
					
				
				
					Proxy caching
					
					
				
				
					Why Varnish?
					
						- Free software under BSD license
 
						- Well documented, free books, good documentation
 
						- Easy to introduce, few code changes
 
						- Good experience at e.g. at XING or OTTO
 
					
				
				
				
					VCL
					
						- DSL to configure request handling / caching policies
 
						- Possible to change/control everything
 
						- Good set of general rules
 
					
				
				
					VCL Flow
					
						- vcl_recv
 
						- vcl_hash
 
						- vcl_hit / vcl_miss
 
						- vcl_backend_fetch
 
						- vcl_backend_response
 
						- vcl_deliver
 
					
				
				
					VCL Flow Chart
					
				
				
					Example routine
					
sub vcl_backend_response {
  # Only cache json response
  if (beresp.http.Content-Type !~ "application/json") {
    set beresp.uncacheable = true;
  }
  return(deliver);
}
					
				
				
					Setting up a cache
					
class APIController
  def index
    expires_in 1.minute, 'stale-while-revalidate': 10.minutes
    header['Vary'] = ['Accept', 'Range']
    render_json
  end
end
					
					
						Server response Header
						
Cache-Control: max-age=60, stale-while-revalidate=600
Vary: Accept, Range
						
					 
				
				
					Cache Invalidation
					
						- Via HTTP Request
 
						- Purging
 
						- Ban list entry
 
					
					
api_client.get('/resource', headers: { 'Cache-Control': 'Purge' })
					
				
				
					Other features
					
						- Call aggregation
 
						- Console tools
 
						- Plugins for Munin, NewRelic, Nagios, etc.
 
					
				
				
				
				
					Cache Invalidation
					Avoid very long ban lists
				
				
					Object expunging
					Provide Varnish with enough Memory
				
				
					Identify suitable calls
					
						- Low diversity
 
						- High request rate
 
						- = Good hitrate
 
					
				
				
					Dedicated Varnish endpoint
					
						- Custom port or subdomain
 
						- Better monitoring
 
						- Explicit usage from client
 
					
				
				
					Summing up
					Varnish provides a convenient option for our API toolbelt