HTTP-Caching mit Varnish

Vortrag bei der LUG Balista am 21.10.2013

von Klaus Kruse (mail@klaus-kruse.de)

Was uns erwartet

  1. Wir werden uns die Hände schmutzig machen und in die Tiefen von HTTP eintauchen
  2. ...und natürlich in Varnish
  3. Fragen bitte Fragen
  4. Spaß haben

First things first

Über mich

Vorbereitung

HTTP

telnet 192.168.1.102 8080
HEAD / HTTP/1.0
Host: nocaching
<Leerzeile>

HTTP/1.1 200 OK
Server: nginx/1.4.2
Date: Fri, 11 Oct 2013 10:44:38 GMT
Content-Type: text/html
Content-Length: 5113
Connection: close
Accept-Ranges: bytes

Caching mit HTTP

Fazit: Caching kann eine tolle Sache sein, wenn man sich (ein bisschen) auskennt

Die drei "W"s

Für den richtigen Einsatz muss man folgende Fragen beantworten können:

  • Wer speichert
  • welchen Content
  • wie lange

idealerweise.

Caching mit HTTP 1.0

curl -I -H "Host: expires" 192.168.1.102:8080
HTTP/1.1 200 OK
Expires: Mon, 21 Oct 2013 10:00:04 GMT
Cache-Control: max-age=259200

Verwendung des Last-Modified-Headers

curl -I -H "Host: lastmodified" 192.168.1.102:8080
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 5113
Last-Modified: Thu, 03 Oct 2013 10:08:47 GMT
curl -I -H "Host: lastmodified"
-H "If-Modified-Since: \
Thu, 03 Oct 2013 10:08:47 GMT" 192.168.1.102:8080
HTTP/1.1 304 Not Modified
Last-Modified: Thu, 03 Oct 2013 10:08:47 GMT

Caching mit HTTP 1.1: ETag

curl -I -H "Host: etag" 192.168.1.102:8080
HTTP/1.1 200 OK
ETag: "5260c47f-2366"
curl -I -H "Host: etag" \
-H "If-None-Match: \"5260c47f-2366\"" \
192.168.1.102:8080
HTTP/1.1 304 Not Modified
ETag: "5260c47f-2366"

Cache-Control Header

curl -I -H "Host: expires" 192.168.1.102:8080
HTTP/1.1 200 OK
Cache-Control: max-age=259200
curl -I -H "Host: publiccache" 192.168.1.102:8080
HTTP/1.1 200 OK
Cache-Control: max-age=259200
Cache-Control: public

Mögliche Cache-Control Werte

Zusammenfassung HTTP Caching

Best Practices

Wofür braucht man einen cachenden Proxy dann?

Cachende Webproxies

Varnish

Varnish konfigurieren

Varnish beobachten

Varnishlog

varnishlog -x CLI,RxHeader,ObjHeader,TxHeader
13 SessionOpen  c 192.168.2.143 56456 :80
13 ReqStart     c 192.168.2.143 56456 685134148
13 RxRequest    c HEAD
13 RxURL        c /
13 RxProtocol   c HTTP/1.1
13 VCL_call     c recv lookup
13 VCL_call     c hash
13 Hash         c /
13 Hash         c 192.168.2.186
13 VCL_return   c hash
13 Hit          c 685134147
13 VCL_call     c hit deliver
13 VCL_call     c deliver deliver
13 TxProtocol   c HTTP/1.1
13 TxStatus     c 200
13 TxResponse   c OK
13 Length       c 0
13 SessionClose c EOF
13 StatSess     c 192.168.2.143 56456 0 1 1 0 0 0 185 0

Funktionsweise von Varnish

HTTP-Requests durchlaufen verschiedene Zustände

Ausführlicher von varnish.org: vcl.png

vcl_recv Teil 1

sub vcl_recv {
    if (req.restarts == 0) {
      if (req.http.x-forwarded-for) {
          set req.http.X-Forwarded-For =
              req.http.X-Forwarded-For + ", " + client.ip;
      } else {
          set req.http.X-Forwarded-For = client.ip;
      }
    }
    if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
        return (pipe);
    }

vcl_recv Teil 2

    if (req.request != "GET" && req.request != "HEAD") {
        return (pass);
    }
    if (req.http.Authorization || req.http.Cookie) {
        return (pass);
    }
    return (lookup);
}

Eintritt in den Cache nur für GET-Request ohne Cookie- oder Auth-Header

vcl_hash

sub vcl_hash {
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    return (hash);
}

vcl_hit und vcl_miss

sub vcl_hit {
    return (deliver);
}

sub vcl_miss {
    return (fetch);
}

vcl_pass

sub vcl_pass {
    return (pass);
}

vcl_fetch

sub vcl_fetch {
    if (beresp.ttl <= 0s ||
        beresp.http.Set-Cookie ||
        beresp.http.Vary == "*") {
              set beresp.ttl = 120 s;
              return (hit_for_pass);
    }
    return (deliver);
}

Wenn der Server einen Cookie setzt, ein "Vary: *" oder ein Expire in der Vergangenheit, wird Content nicht gecached

vcl_deliver

sub vcl_deliver {
    return (deliver);
}

Eigene Konfiguration

Hosts ausschließen

if ( req.http.host ~ "nocaching" ) {
   return (pass);
}
return (lookup);

Gleiche Files zwischen mehreren Hosts

if (req.url ~ "^/(images|css)" ) {
   hash_data(req.url);
   return (hash);
}

Hash wird nur noch aus der URL gebildet

Eigene Header mitgeben

sub vcl_deliver {
set resp.http.X-Hello = "Hello Balista";
set resp.http.TTL  = beresp.ttl ;
return (deliver);
}

Eigene Header mitgeben (2)

sub vcl_fetch {
     if (beresp.ttl <= 0s ||
         beresp.http.Set-Cookie ||
         beresp.http.Vary == "*") {
                set beresp.ttl = 120 s;
                set beresp.http.X-TTL = "0";
                return (hit_for_pass);
     }
     set beresp.http.X-TTL = beresp.ttl ;
     return (deliver);
 }

Tipps

Schluss

SpaceForward
Left, Down, Page DownNext slide
Right, Up, Page UpPrevious slide
POpen presenter console
HToggle this help