Date post: | 15-Apr-2017 |
Category: |
Technology |
Upload: | - |
View: | 526 times |
Download: | 5 times |
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