Hello < me irl
Site Reliability Engineer
“DJANGO ALL THE THINGS!”
“...but
“...but
“...everything
A few vanity metrics.
Monthly Unique Visitors 1,115,080,411
Monthly Page Views 7,516,761,301
...what happened to the other 64%?
Let’s talk about HTTP. Hypertext Transport Protocol
$ curl -v disqus.com
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Request
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Method
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Path
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Version
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Headers
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Response
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Status
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Headers
“Cool,
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > < HTTP/1.1 200 OK < Server: nginx < Date: Fri, 30 Aug 2013 06:38:37 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 10453 < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 06:38:36 GMT < Cache-Control: no-cache, must-revalidate Hmm. What can we do with this information?
> GET / HTTP/1.1 > User-Agent: curl/7.24.0 > Host: disqus.com
> Accept: */* > If-Modified-Since: Fri, 30 Aug 2013 00:32:14 GMT > < HTTP/1.1 304 Not Modified < Server: nginx < Date: Fri, 30 Aug 2013 18:05:38 GMT < Last-Modified: Fri, 30 Aug 2013 00:32:14 GMT < Vary: Accept-Encoding < Expires: Fri, 30 Aug 2013 18:05:37 GMT < Cache-Control: no-cache, must-revalidate
304 Not Modified No body is sent with the response
304 Not Modified Client reuses its cached version
304 Not Modified Usually more efficient to calculate
notbad.gif
But we can do better!
“Far future headers”
Chrome Web Inspector on second visit
No HTTP request 0ms
No HTTP request Computer actually did something right for once
“I SEE WHAT YOU DID THERE” - Hopefully you
Takeaways Clients behave differently depending on the response headers
Takeaways These usually come with minimal effort with static files
Same logic can be applied to dynamic content.
What’s this look like in Django?
“OMG!
Well... not really.
1? 2? 3?
...out of 42k requests per second.
Parsing HTTP.
WSGI.
Django middleware stack.
Do some stuff.
Render a template?
Back out through the Django middleware.
Transform an HttpResponse into a real HTTP response.
...at 42k requests per second.
You’re gonna have a bad time. me
Until now, “client” has been a user’s browser.
“If only we could utilize this Cache-Control stuff better...”
Introducing
$ apt-get install varnish
$ brew install varnish
tl;dr Varnish sits between Django and your users Internet
tl;dr Caches HTTP responses and respects proper HTTP headers Internet
Stand back, science is happening.
Stand back, science is happening. benchmarking
Simple, non-scientific “Hello World”
Varnish: How does it work?
First request
First response “Lemme
“Yo,
Next response “wut
Caching: ProMoves™
Augment with JavaScript Update your UI optimistically
Augment with JavaScript Leverage cookies to store non-critical data
Augment with JavaScript Defer fetching user-specific data until needed
Let’s meet: John and Jane Doe.
John and Jane are different users.
John logs into Disqus.
Jane logs into Disqus.
Jane sees John’s stuff.
Jane sees John’s stuff. ^ not
We really want to avoid this from ever happening.
Cookies
How do users even work?
Unique id that represents a logged in user Session Id
django.contrib.sessions / django.contrib.auth Session Id
Could potentially cache per session id Session Id
If it doesn’t, Varnish can normalize it.
Learn: Varnish Configuration Language (VCL) in 30 seconds
Basically, caching is hard.
Go make some stuff faster.
We’re hiring people who hate computers. disqus.com/jobs