Bulgaria PHP Conference, September 25th, 2015
apt-get install varnish
apt-get install varnish
/etc/default/varnish
, replace port 6081 by port 80service apache2 restart service varnish restart
httpstatusdogs.com
GET /path HTTP/1.1 200 OK Content-Type: text/html <html>...</html>
twitter.com/stevelosh/status/372740571749572610
wget -Sq --spider varnish.lo/solutions/expiration.php curl -o /dev/null -sD - varnish.lo/solutions/expiration.php
HTTP 1.1, RFC 2616, Sections 13.2 and 13.3
Cache-Control: s-maxage=3600, max-age=900 Expires: Thu, 15 May 2014 08:00:00 GMT
curl -sD - varnish.lo/noinfo.php curl -sD - varnish.lo/exercises/expiration.php
ETag: 82901821233
If-None-Match: 82901821233 304 Not Modified
curl -sD - varnish.lo/exercises/etag.php curl -H "If-None-Match: abc" -sD - varnish.lo/exercises/etag.php
Last-Modified: Tue, 13 May 2014 08:13:20 GMT
If-Modified-Since: Tue, 13 May 2014 08:13:20 GMT 304 Not Modified
curl -sD - varnish.lo/exercises/last-modified.php curl -H "If-Modified-Since: {previous timestamp}" -sD - varnish.lo/exercises/last-modified.php
gmdate('r')
does not work as timezone is output as "+0000" instead of "GMT".Cache-Control: s-maxage=0, private, no-cache
www.varnish-cache.org/trac/browser/bin/varnishd/default.vcl?rev=3.0 (Varnish 3)
www.varnish-cache.org/trac/browser/bin/varnishd/builtin.vcl?rev=4.0 (Varnish 4)
curl -sD - varnish.lo/exercises/nocache.php
curl -sD - varnish.lo/cookie.php curl -H "Cookie: x" -sD - varnish.lo/solutions/expiration.php
GET /resource Accept: application/json
GET /resource Accept: text/xml
Vary: Accept
curl -sD - varnish.lo/exercises/content-negotiation.php curl -H "Accept: application/json" -sD - varnish.lo/exercises/content-negotiation.php
Think carefully and test thoroughly
sub vcl_backend_response { set beresp.http.X-TTL = beresp.ttl; } sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } }
backend default { .host = "127.0.0.1"; .port = "8080"; } backend legacy { .host = "127.0.0.1"; .port = "8000"; } sub vcl_recv { if (req.url ~ "^/archive/") { set req.backend_hint = legacy; } else { set req.backend_hint = default; } }
sub vcl_recv { if (req.http.Cookie) { if (req.url ~ "^/cache") { remove req.http.Cookie; } } }
curl -H "Cookie: x" -sD - varnish.lo/solutions/expiration.php
header('X-Reverse-Proxy-TTL: 30');
C{ #include <stdlib.h>; }C sub vcl_backend_response { if (beresp.http.X-Reverse-Proxy-TTL) { C{ char *ttl; const struct gethdr_s hdr = { HDR_BERESP, "\024X-Reverse-Proxy-TTL:" }; ttl = VRT_GetHdr(ctx, &hdr); VRT_l_beresp_ttl(ctx, atoi(ttl)); }C unset beresp.http.X-Reverse-Proxy-TTL; } } ...
# config/varnish/common.vcl include "custom-ttl.vcl";
sudo service varnish restart
curl -sD - varnish.lo/exercises/custom-ttl.php
Average number of requests over last 60 seconds
varnishtop
Top URLs that are missing the cache:
varnishtop -i BereqUrl
Client or backend only:
varnishtop -c varnishtop -b
Show header values:
varnishtop -I ReqHeader:Cookie
Log all the things:
varnishlog
Again, only client or backend:
varnishlog -c varnishlog -b
Log entries for specific URL:
varnishlog -q 'ReqUrl ~ "/exercises"' varnishlog -q 'BereqUrl ~ "/exercises"'
<< Request >> 32770 - Begin req 32769 rxreq - Timestamp Start: 1433683498.334761 0.000000 0.000000 - Timestamp Req: 1433683498.334761 0.000000 0.000000 - ReqStart 127.0.0.1 45447 - ReqMethod PURGE - ReqURL /cache.php - ReqProtocol HTTP/1.1 - ReqHeader User-Agent: GuzzleHttp/6.0.1 curl/7.38.0 PHP/5.6.7-1 - ReqHeader Host: localhost:6181 - ReqHeader X-Forwarded-For: 127.0.0.1 - VCL_call RECV - VCL_acl MATCH invalidators "127.0.0.1" - VCL_return purge - VCL_call HASH - VCL_return lookup - VCL_call PURGE - Debug "VCL_error(201, PURGED!)" - VCL_return synth - Timestamp Process: 1433683498.334931 0.000170 0.000170 - RespHeader Date: Sun, 07 Jun 2015 13:24:58 GMT - RespHeader Server: Varnish - RespHeader X-Varnish: 32770 - RespProtocol HTTP/1.1 - RespStatus 201 - RespReason Created - RespReason PURGED! - VCL_call SYNTH - RespHeader Content-Type: text/html; charset=utf-8 - RespHeader Retry-After: 5 - VCL_return deliver - RespHeader Content-Length: 243 - Debug "RES_MODE 2" - RespHeader Connection: keep-alive - Timestamp Resp: 1433683498.334985 0.000224 0.000054 - ReqAcct 105 0 105 197 243 440
varnishlog
and varnishtop
curl -sD - varnish.lo/solutions/content-negotiation.php curl -H "Accept: application/json" -sD - varnish.lo/solutions/content-negotiation.php
Accept
header.varnishtop -I ReqHeader:'Accept:'
varnishlog -I ReqHeader:'Accept:'
vendor/friendsofsymfony/http-cache/tests/Functional
Run the tests:
vendor/bin/phpunit
Edit the test:
tests/CacheTest.php
Edit the code:
web/exercises/post.php
Make it green!
<link rel="stylesheet" href="/css/style.css?v1" type="text/css"/> ... <script src="/js/scripts.js?v1"></script>
acl invalidators { "localhost"; } if (req.method == "PURGE") { if (!client.ip ~ invalidators) { return (synth(405, "Not allowed")); } return (purge); } ...
# config/varnish/common.vcl include "invalidation.vcl";
sudo service varnish restart
curl -sD - varnish.lo/solutions/expiration.php curl -X PURGE -sD - varnish.lo/solutions/expiration.php curl -sD - varnish.lo/solutions/expiration.php
curl -sD - varnish.lo/invalidation/ curl -X POST --data 'method=Purge' -sD - varnish.lo/invalidation/update.php curl -sD - varnish.lo/invalidation/ curl -X POST --data 'method=Refresh' -sD - varnish.lo/invalidation/update.php curl -sD - varnish.lo/invalidation/
curl -sD - varnish.lo/invalidation/?x curl -X POST --data 'method=Purge' -sD - varnish.lo/invalidation/update.php curl -sD - varnish.lo/invalidation/?x curl -X POST --data 'method=Ban' -sD - varnish.lo/invalidation/update.php curl -sD - varnish.lo/invalidation/?x
ban("obj.http.x-cache-tags ~ " + req.http.x-cache-tags );
curl -sD - varnish.lo/exercises/tagging/?filter=apple curl -sD - varnish.lo/exercises/tagging/?filter=orange curl -X POST --data 'applepie=New description' -sD - varnish.lo/exercises/tagging/update.php curl -sD - varnish.lo/exercises/tagging/?filter=apple curl -sD - varnish.lo/exercises/tagging/?filter=orange
/** @var $cm CacheManageer */ $cm->tagResponse($response, array('comment-42')); ... $cm->invalidateTags(array('comment-42'));
use FOS\HttpCacheBundle\Configuration\Tag; class CommentController extends Controller { /** * @Tag({"comments", "'comment-'~id"}) */ public function commentAction($id) // ...
<html> <body> Main body. <esi:include src="fragment.php" /> </body> </html>
-p esi_syntax=0x00000003
sub vcl_recv { // Add a Surrogate-Capability header // to announce ESI support. set req.http.Surrogate-Capability = "abc=ESI/1.0"; } sub vcl_backend_response { // Check for ESI acknowledgement // and remove Surrogate-Control header. if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; set beresp.do_esi = true; } }
# config/varnish/common.vcl include "esi.vcl";
sudo service varnish restart
curl -sD - varnish.lo/exercises/esi/ curl -sD - varnish.lo:8080/exercises/esi/ curl -sD - varnish.lo/exercises/esi/fragment.php
# app/config/config.yml framework: esi: { enabled: true } fragments: { path: /_fragment }Make sure either your webserver is only reachable from the Varnish server or add access restrictions for /_fragment
{# index.html.twig #} {% render_esi(controller( 'AppBundle:Comments:comments', {'param': 42 })) %}
sub vcl_recv { set req.http.cookie = ";" + req.http.cookie; set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); set req.http.cookie = regsuball(req.http.cookie, ";(PHPSESSID)=", "; \1="); set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", ""); if (req.http.Cookie == "") { remove req.http.Cookie; } }
varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies #RemovingallBUTsomecookies
if (isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time()-3600); }varnish.lo/limit-session/ (with your browser)
Group based caching
# config/varnish/common.vcl include "custom-ttl.vcl"; include "user-context.vcl";
sudo service varnish restartvarnish.lo/user-context/ (with your browser)