Varnish for PHP developers (LaraconEU 2016)

Varnish for PHP developers (LaraconEU 2016)

Varnish has the ability to reduce server load, improve page speeds and help scale an application from a couple of hundred users to tens of thousands. But Varnish isn't easy.

This talk guides you through what Varnish is, how it works and leaves you with practical pointers to implement it on your own infrastructure.

6050b4913a2f5cfb09a1cdb31ea489ed?s=128

Mattias Geniar

August 23, 2016
Tweet

Transcript

  1. VARNISH FOR PHP DEVELOPERS

  2. WHAT'S THIS TALK ABOUT?

  3. HI, I'M MATTIAS GENIAR!

  4. None
  5. WHAT IS VARNISH?

  6. IMPORTANT VARNISH VERSIONS

  7. WHY USE VARNISH?

  8. None
  9. REMINDER: HTTP HEADERS

  10. REQUEST HEADERS

  11. GET / HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate Host: ma.ttias.be

    User-Agent: Chrome/52 Cookie: laravel_session=eyJpdiI6...
  12. RESPONSE HEADERS HTTP/1.1 200 OK Cache-Control: private, max-age=0 Content-Encoding: gzip

    Content-Length: 9944 Content-Type: text/html; charset=UTF-8 Server: Apache Date: Tue, 23 Aug 2016 14:15:50 GMT
  13. None
  14. HOW VARNISH WORKS

  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. None
  25. None
  26. None
  27. None
  28. VARNISH CONFIGURATION LANGUAGE $ cat /etc/varnish/default.vcl vcl 4.0; sub vcl_recv

    { } sub vcl_backend_response { } sub vcl_backend_fetch { } sub vcl_deliver { }
  29. MANIPULATING THE CLIENT REQUEST sub vcl_recv { # Only cache

    GET or HEAD requests. if (req.method != "GET" && req.method != "HEAD") { return (pass); } # Remove any Google Analytics based cookies set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", ""); ... }
  30. MANIPULATING THE CLIENT REQUEST sub vcl_recv { if (req.http.host ~

    "^(www\.)?domain\.tld$" || req.http.host ~ "test"){ set req.backend = specific_backend; return (pass); } }
  31. MANIPULATING THE CLIENT REQUEST sub vcl_recv { if (req.url ~

    "^[^?]*\.(css|gif|gz|ico|jpeg|jpg|js|png|xml)(\?.*)?$") { unset req.http.Cookie; return (lookup); } }
  32. MANIPULATING THE RESPONSE sub vcl_backend_response { if (bereq.url ~ "^[^?]*\.(css|gif|gz|ico|jpeg|jpg|js|png|xml)(\?.*)?$")

    { unset bereq.http.Set-Cookie; # Case insensitive headers return (deliver); } }
  33. MANIPULATING THE RESPONSE sub vcl_backend_response { # Don't cache 50x

    responses if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503) { return (abandon); } # Allow stale content, in case the backend goes down. # make Varnish keep all objects for 2 hours beyond their TTL set beresp.grace = 2h; }
  34. MANIPULATING THE DELIVERY sub vcl_deliver { if (obj.hits > 0)

    { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } set resp.http.X-Cache-Hits = obj.hits; unset resp.http.X-Powered-By; unset resp.http.Server; }
  35. CHALLENGE: VISUALISING CHANGES

  36. EXAMPLE +

  37. None
  38. None
  39. None
  40. None
  41. None
  42. None
  43. DETERMINING HASH KEYS sub vcl_hash { hash_data(req.url); // ie: /blog/your-clickbait-title

    hash_data(req.http.host); // ie: ma.ttias.be hash_data(req.http.Cookie); // ie: language=nl }
  44. CHALLENGE: URLS sub vcl_recv { # Sort all query arguments

    set req.url = std.querysort(req.url); // ie: "?lang=nl&p=5" == "?p=5&lang=nl" # Remove GA tags: domain.tld?utm_source=email&utm_medium=buffer&... set req.url = regsuball(req.url, "(utm_source|utm_medium|...)=(...)", ""); }
  45. CHALLENGE: COOKIES sub vcl_hash { // ... hash_data(req.http.Cookie); // ie:

    language=nl }
  46. CHALLENGE: COOKIES import cookie; sub vcl_recv { # Use libvmod-cookie,

    parse the "Cookie:" header from the client cookie.parse(req.http.cookie); # Filter all except these cookies from it cookie.filter_except("laravel_session,custom_cookie"); # Set the "Cookie:" header back to the parsed/filtered value set req.http.cookie = cookie.get_string(); }
  47. CHALLENGE: HOST sub vcl_recv { # domain.tld vs www.domain.tld, force

    www subdomain if (req.http.host == "domain.tld") { return (synth(720, "http://www.domain.tld")); } } sub vcl_synth { if (resp.status == 720) { set resp.http.Location = resp.reason; set resp.status = 301; return (deliver); } }
  48. CACHING API REQUESTS sub vcl_hash { hash_data(req.url); // ie: /api/companies/5/products

    hash_data(req.http.host); // ie: ma.ttias.be if (req.http.Authorization) { hash_data(req.http.Authorization); // ie: Bearer Access-Token } if (req.http.X-Custom-Header) { hash_data(req.http.X-Custom-Header); // ie: app specific } }
  49. None
  50. FLUSHING THE CACHE

  51. PURGE REQUEST acl purge { "localhost"; "192.168.55.0"/24; } sub vcl_recv

    { # allow PURGE from localhost and 192.168.55... if (req.method == "PURGE") { if (!client.ip ~ purge) { return(synth(405,"Not allowed.")); } return (purge); } } $ curl -X PURGE -H "Host: domain.tld" http://31.193.180.217/blog/page1
  52. BAN REQUEST $ varnishadm \ -S /etc/varnish/secret \ "ban req.http.host

    ~ (www.)?domain.tld" $ varnishadm \ -S /etc/varnish/secret \ -T 31.193.180.217:6082 \ "ban req.http.host ~ www.domain.tld && req.url ~ .css" $ cat /etc/varnish/secret yb9exW6O57c77b9T9lHxkLAShsJ-QbXAdB7CMlGegGK1Q5ViJ5NTwRW
  53. None
  54. EDGE SIDE INCLUDES

  55. None
  56. None
  57. <html> <body> <div class="navi"> <esi:include src="/partial/navi" /> <?php /* include

    'footer.php'; */ ?> </div> <div class="content"> <esi:include src="/partial/content" /> </div> <div class="content"> <!-- load content block twice --> <esi:include src="/partial/content" /> </div> </body> </html>
  58. None
  59. TTL: HOW LONG TO CACHE? header("Cache-Control: public, max-age=900"); sub vcl_backend_response

    { if (bereq.url ~ "/blog/post-on-hackernews") { set beresp.ttl = 600s; return (deliver); } }
  60. GRACE MODE sub vcl_backend_response { # All objects get a

    10 minute cache lifetime set beresp.ttl = 10m; # But just in case, keep objects in cache for an extra 20 min # Can be served to clients while fetching new content # Total time object can be in the cache: 10min + 20min = 30min set beresp.grace = 20m; }
  61. None
  62. varnishhist

  63. varnishlog

  64. varnishncsa

  65. None
  66. GETTING STARTED

  67. THANK YOU!