varnish cache and django (falcon, flask etc)
TRANSCRIPT
djangoacceleration with Varnish
django meets requestIntroduction1.
django meets requestIntroduction1.
Django Framework Architecture
RDBMS
ORM
Model
Storage
View
Template
Template Loader
FormsSignals
Middleware
Request
Middleware
URL Resolver
Response
HTTP Request
GET /wiki/HTTP HTTP/1.1 Host: ru.wikipedia.org Cookie: name=value
HTTP Request and Response
HTTP/1.1 200 OK Version: HTTP/1.1 Age: 165734 Last-Modified: Wed, 30 Mar 2016 20:48:23 GMT Cache-Control: private, s-maxage=0, max-age=0, must-revalidate Content-Encoding: gzip Content-Language: ru Content-Length: 50565 Content-Type: text/html; charset=UTF-8 Date: Fri, 01 Apr 2016 18:50:51 GMT Server: Apache Status: 200 OK Vary: Accept-Encoding,Cookie,Authorization Via: 1.1 varnish, 1.1 varnish X-Cache: cp1052 miss(0), cp3033 hit(4), cp3032 frontend hit(185) Set-Cookie: name=value
(Body Content)
GET /wiki/HTTP HTTP/1.1 Host: ru.wikipedia.org Cookie: name=value
Application Architecture
nginx
uWSGI
django-app
database
Request Response
Application Architecture with Varnish
nginx
uWSGI
django-app
Varnish
uWSGI
django-app
database
GET, HEAD
Request Response
we meet VarnishAcquaintance2.
Varnish
Reverse HTTP Proxy In-memory time based cache Varnish cache is key-value store Big “state” machine Load balancing (backend health check)
By Default
Cacheable methods: GET, HEAD Cacheable response codes:
- 200, 203 - 300, 301, 302 - 404, 410
Requests without cookies Default key: req.url + req.http.host
Varnish Configuration Language
The VCL is a small domain-specific language designed to be used to define request handling and document caching policies for the Varnish HTTP accelerator.
Varnish State Machine
request
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
vcl_recv routine
request
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
vcl_recv routine
Request normalization Request transformation (GET, Cookies) Document caching policies Load balancing Health checking Access control (synth(403) on BAN from WAN).
vcl_recv routinesub vcl_recv { unset req.http.User-Agent;
if (req.method != "GET" && req.method != "HEAD") { return (pass); }
if (req.http.Authorization) { return (pass); # Not cacheable by default } // Some people, when confronted with a problem, think // “I know, I'll use regular expressions." - Now they have two problems.
if (req.http.Cookie ~ "sessionid") { set req.http.x-sessionid = regsub( req.http.Cookie,"^.*?sessionid=([^;]*);*.*$" , "\1" ); } }
vcl_hash routine
request
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
vcl_hash
# The data on which the hashing will take place sub vcl_hash {
hash_data(req.url);
if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); }
# hash cookies for requests that have them if (req.http.Cookie) { hash_data(req.http.Cookie); } }
vcl_backend_fetch and vcl_backend_response routines
request
vcl_recv
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
vcl_hash
Backend configuration
backend server1 { # Define one backend .host = "127.0.0.1"; # IP or Hostname of backend .port = "80"; # Backend Port .max_connections = 300; # That’s it
.probe = { #.url = "/"; # short easy way (GET /) # We prefer to only do a HEAD / .request = "HEAD / HTTP/1.1" "Host: localhost" "Connection: close" "User-Agent: Varnish Health Probe";
.interval = 5s; # check the health of each backend every 5 seconds .timeout = 1s; # timing out after 1 second. .window = 5; # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick .threshold = 3; }
.first_byte_timeout = 300s; # How long to wait before we receive a first byte from our backend? .connect_timeout = 1s; # How long to wait for a backend connection? .between_bytes_timeout = 2s; # How long to wait between bytes received from our backend? }
vcl_backend_fetch and vcl_backend_response routines
sub vcl_backend_response {
if (beresp.http.X-Varnish-TTL) { set beresp.ttl = std.duration( beresp.http.X-Varnish-TTL + "s", 120s); } else { set beresp.uncacheable = true; }
# Add debug info to response set beresp.http.X-Debug-Backend = beresp.backend.name; set beresp.http.X-Debug-Now = now; set beresp.http.X-Debug-TTL = beresp.ttl; set beresp.http.X-Debug-Cookie = beresp.http.Cookie; set beresp.http.X-Debug-Set-Cookie = beresp.http.Set-Cookie;
# Turn on ESI set beresp.do_esi = true; } }
Varnish State Machine
request
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
two hard things in CSСache invalidation2.1
“There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton
Cache invalidation
acl admin { # ACL we will use later to allow purges "localhost"; "127.0.0.1"; }
sub vcl_recv { # Purge cache by url if (req.method == "PURGE") { if (client.ip ~ local) { return(purge); } else { return(synth(403, "Forbidden.")); } } }
Cache invalidation
sub vcl_recv { # Ban cache by pattern if (req.method == "BAN") { if (!client.ip ~ local) { return(synth(403, "Forbidden.")); } ban("obj.http.X-URL ~ " + req.url); # req.url is a regex return(synth(200, "Ban added")); } }
Cache invalidation
!→ ˜ curl -X PURGE http://worldofwarships.ru/news/itgm-7.html
!→ ˜ curl -X BAN http://worldofwarhips.ru/news/\*
Cache invalidationdef send_ban(url): """Issue a HTTP request with BAN method to Varnish :param url: a path or regexp to ban (invalidate) :return: None """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((varnish_settings.HOST, varnish_settings.PORT)) except socket.error: logger.exception('Varnish not available') else: sock.sendall("BAN %s HTTP/1.1\r\nHost: %s\r\n\r\n" % ( url, varnish_settings.HOST )) http_status, body = response.split("\n", 1) _, status, text = http_status.split(" ", 2) if status == "%s" % httplib.OK: pass finally: sock.close()
Cookies
By default Varnish don't cache requests with CookiesBut!
Cookies
request
vcl_recv
vcl_hash
vcl_hit
vcl_pass
vcl_miss
vcl_deliver
response
vcl_backend_fetch
vcl_backend_response
backend
vcl_recv: cookies -> HTTP headers. vcl_hash: add headers to hash vcl_backend_fetch: restore cookie header
Grace period
Grace in the scope of Varnish means delivering otherwise expired objects when circumstances call for it. This can happen because: - The backend-director selected is down; - A different thread has already made a request to the backend that's not yet finished.
sub vcl_backend_response { set beresp.grace = 1d; }
ESI
Edge Side Includes language, which allows content assembly by HTTP surrogates
<html> <body> The time is: <esi:include src=“/cgi-bin/date.cgi"/> at this very moment. </body> </html>
#/cgi-bin/date.cgi #!/bin/sh
echo 'Content-type: text/html' echo '' date "+%Y-%m-%d %H:%M"
ESI
ESI
django meets VarnishIntegration3.
Django Integration
RDBMS
ORM
Model
Storage
View
Template
Template Loader
FormsSignals
Middleware
Response
Middleware
URL Resolver
Request
Django Integration
Function Based [email protected](cache_timeout=60) def mainpage_view(request, template_name="mainpage/index.html"): return HttpResponse(render_to_string(template_name))
class MainPageView(varnish.CacheControlMixin, TemplateView): cache_timeout = 60 template_name = 'mainpage/index.html'
Class Based View
Varnish utils4.
Utils
varnishncsa — presents them in the Apache / NCSA "combined" log format;
varnishstat — general statistics; varnishtop — presents a continuously updated list of
the most commonly occurring log entries; varnishhist — presents a continuously updated
histogram showing the distribution of the last N requests by their processing.
Varnishhist
Сonclusion5.
๏ Django ๏ HTTP Request and Response ๏ Varnish Configuration Language ๏ Varnish State Machine ๏ Cache invalidate ๏ Django integration