Slide 1

Slide 1 text

Varnish training Varnishcon Amsterdam 2016 By Thijs Feryn

Slide 2

Slide 2 text

Slow websites suck

Slide 3

Slide 3 text

Web performance is an essential part of the user experience

Slide 4

Slide 4 text

Web performance matters

Slide 5

Slide 5 text

Varnish could solve that problem

Slide 6

Slide 6 text

Hi, I’m Thijs

Slide 7

Slide 7 text

I’m @ThijsFeryn on Twitter

Slide 8

Slide 8 text

I’m an Evangelist At

Slide 9

Slide 9 text

I’m an at Evangelist

Slide 10

Slide 10 text

I’m a at board member

Slide 11

Slide 11 text

Varnish

Slide 12

Slide 12 text

Cache?

Slide 13

Slide 13 text

Loadbalancer?

Slide 14

Slide 14 text

Proxy?

Slide 15

Slide 15 text

Web application firewall?

Slide 16

Slide 16 text

HTTP accelerator

Slide 17

Slide 17 text

Why Cache?

Slide 18

Slide 18 text

Run out of ways to optimize their application stack

Slide 19

Slide 19 text

Infrastructure or code optimization would cost too much money

Slide 20

Slide 20 text

Don’t recompute if the data hasn’t changed

Slide 21

Slide 21 text

Varnish is really fast !!!

Slide 22

Slide 22 text

In memory

Slide 23

Slide 23 text

Threading

Slide 24

Slide 24 text

Varnish Configuration Language

Slide 25

Slide 25 text

Reverse proxy

Slide 26

Slide 26 text

Normally User Server

Slide 27

Slide 27 text

With forward proxy User Proxy Server Office

Slide 28

Slide 28 text

With reverse proxy User Proxy Server Datacenter

Slide 29

Slide 29 text

Install & configure

Slide 30

Slide 30 text

apt-get install apt-transport-https curl https://repo.varnish-cache.org/GPG- key.txt | apt-key add - echo "deb https://repo.varnish-cache.org/ debian/ jessie varnish-4.1"\ >> /etc/apt/sources.list.d/varnish- cache.list apt-get update apt-get install varnish Debian

Slide 31

Slide 31 text

apt-get install apt-transport-https curl https://repo.varnish-cache.org/GPG- key.txt | apt-key add - echo "deb https://repo.varnish-cache.org/ ubuntu/ trusty varnish-4.1"\ >> /etc/apt/sources.list.d/varnish- cache.list apt-get update apt-get install varnish Ubuntu

Slide 32

Slide 32 text

yum install epel-release rpm --nosignature -i https://repo.varnish- cache.org/redhat/varnish-4.1.el7.rpm yum install varnish RHEL & CentOS 7

Slide 33

Slide 33 text

yum install epel-release rpm --nosignature -i https://repo.varnish- cache.org/redhat/varnish-4.1.el6.rpm yum install varnish RHEL & CentOS 6

Slide 34

Slide 34 text

Config file

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

SysV Systemd Ubuntu/Debian /etc/default/varnish /etc/systemd/system/ varnish.service RHEL/CentOS /etc/sysconfig/varnish /etc/varnish/ varnish.params

Slide 37

Slide 37 text

cp /lib/systemd/system/varnish.service \ /etc/systemd/system/ Copy defaults file Ubuntu & Debian with systemd

Slide 38

Slide 38 text

Startup options

Slide 39

Slide 39 text

[Unit] Description=Varnish Cache, a high- performance HTTP accelerator [Service] Type=forking LimitNOFILE=131072 LimitMEMLOCK=82000 ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m ExecReload=/usr/share/varnish/reload-vcl [Install] WantedBy=multi-user.target Debian Jessie with systemd

Slide 40

Slide 40 text

vim /etc/systemd/system/varnish.service systemctl daemon-reload service varnish reload Reload with systemd

Slide 41

Slide 41 text

DAEMON_OPTS="-a :80 \ -T localhost:6082 \ -f /etc/varnish/default.vcl \ -S /etc/varnish/secret \ -s malloc,256m" Ubuntu Trusty without systemd

Slide 42

Slide 42 text

vim /etc/default/varnish service varnish reload Reload with sysv

Slide 43

Slide 43 text

-a: binding address & port -T: admin binding -f: VCL file -S: secret file -s: storage -j: jailing -l: shared memory log size -t: default TTL -p: runtime parameters Options

Slide 44

Slide 44 text

DAEMON_OPTS="-j unix,user=www-data \ -a :80 \ -a :81,PROXY \ -T localhost:6082 \ -f /etc/varnish/default.vcl \ -S /etc/varnish/secret \ -l 100m,10m \ -t 60 \ -p feature=+esi_disable_xml_check \ -p connect_timeout=20s \ -p first_byte_timeout=100s \ -p between_bytes_timeout=5s \ -s malloc,3g"

Slide 45

Slide 45 text

The backend

Slide 46

Slide 46 text

80

Slide 47

Slide 47 text

Point of entry? Bind to 80 Otherwise 6081

Slide 48

Slide 48 text

8080 HTTP-ALT

Slide 49

Slide 49 text

Listen 8080 Apache ports.conf vhost

Slide 50

Slide 50 text

listen 8080; Nginx vhost

Slide 51

Slide 51 text

✓In VCL file ✓In config file using "-b" Link backend to Varnish

Slide 52

Slide 52 text

DAEMON_OPTS="-j unix,user=www-data \ -a :80 \ -a :81,PROXY \ -T localhost:6082 \ -b 127.0.0.1:8080 \ -S /etc/varnish/secret \ -s malloc,3g" Can't have -f In config file

Slide 53

Slide 53 text

vcl 4.0;
 
 backend default {
 .host = "127.0.0.1";
 .port = "8080";
 } In VCL file Minimal VCL

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

There are rules

Slide 56

Slide 56 text

✓ Idempotence ✓ State ✓ TTL ✓ Variations Varnish and HTTP

Slide 57

Slide 57 text

Idempotence Execute multiple times Result doesn't change

Slide 58

Slide 58 text

✓ GET ✓ HEAD - POST - PUT - DELETE - PATCH Idempotence Result changes Result doesn't change Don't cache

Slide 59

Slide 59 text

State

Slide 60

Slide 60 text

State ~ user specific data Cookies Auth headers

Slide 61

Slide 61 text

About cookies

Slide 62

Slide 62 text

✓ Request header ✓ Sent by client (~browser) ✓ Sent on every request ✓ Describes state ✓ Is not cached ✓ 3rd party tracking cookies vs own cookies About cookies Cookie: key=value;key2=value2

Slide 63

Slide 63 text

✓ Response header ✓ Sent by backend server ✓ Only when backend is called ✓ Changes state ✓ Is not cached ✓ Blacklisted for 120s (by default) About cookies Set-Cookie: key=another_value

Slide 64

Slide 64 text

Time To Live

Slide 65

Slide 65 text

✓ 120s by default ✓ Respects HTTP cache-control header ✓ Respects expires header ✓ Override in VCL file Time to live

Slide 66

Slide 66 text

1.VCL 2.s-maxage 3.max-age 4.expires 5.Default value 120s TTL Order

Slide 67

Slide 67 text

Use TTL not to cache Cache-Control: max-age=0 Cache-Control: s-maxage=0 Cache-Control: private Cache-Control: no-cache Cache-Control: no-store Expires: Fri, 1 Jan 1971 00:00:00 GMT

Slide 68

Slide 68 text

Combine values Cache-Control: public, max- age=1000, s-maxage=3600

Slide 69

Slide 69 text

Age Age: 10 How old is the cached object?

Slide 70

Slide 70 text

Real cache duration max-age - Age s-maxage - Age

Slide 71

Slide 71 text

Variations

Slide 72

Slide 72 text

Cache is not the same for everyone

Slide 73

Slide 73 text

✓ URL ✓ Hostname ✓ IP if hostname is not set ✓ Vary header Basic variations

Slide 74

Slide 74 text

Vary header Vary: Accept-Encoding Vary: Accept-Language Vary: Cookie Watch out!

Slide 75

Slide 75 text

The flow

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

Varnish Configuration Language

Slide 79

Slide 79 text

Hooks & subroutines

Slide 80

Slide 80 text

VCL Recv VCL Hash VCL Miss VCL Hit VCL Backend Response VCL Deliver VCL Purge VCL Error VCL Pipe VCL Pass VCL Synth VCL Backend Error

Slide 81

Slide 81 text

✓vcl_recv: receive request ✓vcl_hash: compose cache key ✓vcl_miss: not found in cache ✓vcl_hit: found in cache ✓vcl_pass: don’t store in cache ✓vcl_pipe: bypass cache ✓vcl_backend_fetch: connect to backend ✓vcl_backend_response: response from backend ✓vcl_backend_error: backend fetch failed

Slide 82

Slide 82 text

✓vcl_purge: after successful purge ✓vcl_synth: send synthetic output ✓vcl_deliver: return data to client ✓vcl_init: initialize VMODs ✓vcl_fini: discard VMODs

Slide 83

Slide 83 text

Actions

Slide 84

Slide 84 text

✓ hash: lookup in cache ✓ pass: don't cache ✓ synth: synthetic HTML output ✓ pipe: bypass cache ✓ purge: remove from cache VCL_RECV

Slide 85

Slide 85 text

✓ synth: synthetic HTML output ✓ pipe: bypass cache VCL_PIPE

Slide 86

Slide 86 text

✓ fetch: fetch data from backend, don't cache ✓ restart: restart transaction ✓ synth: synthetic HTML output VCL_PASS

Slide 87

Slide 87 text

✓ deliver: send cached object ✓ miss: synchronous refresh despite hit ✓ pass: fetch data from backend despite hit, don't cache ✓ restart: restart transaction ✓ synth: synthetic HTML output VCL_HIT

Slide 88

Slide 88 text

✓ fetch: fetch data from backend ✓ pass: fetch data from backend, don't cache ✓ restart: restart transaction ✓ synth: synthetic HTML output VCL_MISS

Slide 89

Slide 89 text

✓ lookup: look for cached object by using hash key VCL_HASH

Slide 90

Slide 90 text

✓ restart: restart transaction ✓ synth: synthetic HTML output VCL_PURGE

Slide 91

Slide 91 text

✓ deliver: deliver object to client ✓ restart: restart transaction ✓ synth: synthetic HTML output VCL_DELIVER

Slide 92

Slide 92 text

✓ deliver: deliver synthetic output to client ✓ restart: restart transaction VCL_SYNTH

Slide 93

Slide 93 text

✓ fetch: fetch object from backend ✓ abandon: abandon request and send HTTP 503 error VCL_BACKEND_FETCH

Slide 94

Slide 94 text

✓ deliver: send fetched data to client ✓ abandon: abandon request and send HTTP 503 error ✓ retry: retry backend request VCL_BACKEND_RESPONSE

Slide 95

Slide 95 text

✓ deliver: send fetched data to client ✓ retry: retry backend request VCL_BACKEND_ERROR

Slide 96

Slide 96 text

Objects

Slide 97

Slide 97 text

✓ req: incoming request object ✓ req_top: top level esi request ✓ bereq: request object to send to backend ✓ beresp: backend response ✓ resp: response to send back to client ✓ obj: cached object ✓ client: client information ✓ server: server information ✓ local: local TCP information ✓ remote: remote TCP information ✓ storage: storage information VCL Objects

Slide 98

Slide 98 text

Variables

Slide 99

Slide 99 text

✓ req.url ✓ req.http.host ✓ req.http.user-agent ✓ req.backend_hint ✓ req.method ✓ … req variables

Slide 100

Slide 100 text

✓ bereq.backend ✓ bereq.http.user-agent ✓ bereq.method ✓ bereq.url ✓ … bereq variables

Slide 101

Slide 101 text

✓ beresp.age ✓ beresp.backend.ip ✓ beresp.backend.name ✓ beresp.do_esi ✓ beresp.grace ✓ beresp.keep ✓ beresp.http.set-cookie ✓ beresp.ttl ✓ beresp.status ✓ beresp.uncacheable beresp variables

Slide 102

Slide 102 text

✓ beresp.age ✓ beresp.backend.ip ✓ beresp.backend.name ✓ beresp.do_esi ✓ beresp.grace ✓ beresp.keep ✓ beresp.http.set-cookie ✓ beresp.ttl ✓ beresp.status ✓ beresp.uncacheable beresp variables

Slide 103

Slide 103 text

✓ client.ip ✓ client.identity client variables local variables ✓ local.ip remote variables ✓ remote.ip

Slide 104

Slide 104 text

✓ obj.age ✓ obj.grace ✓ obj.hits ✓ obj.http.cache-control ✓ obj.reason ✓ obj.status ✓ obj.ttl object variables

Slide 105

Slide 105 text

✓ resp.http.user-agent ✓ resp.is_streaming ✓ resp.reason ✓ resp.status resp variables

Slide 106

Slide 106 text

✓ storage..free_space ✓ storage..used_space ✓ storage..happy storage variables

Slide 107

Slide 107 text

Default behaviour

Slide 108

Slide 108 text

vcl 4.0; sub vcl_recv { if (req.method == "PRI") { return (synth(405)); } if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "DELETE") { return (pipe); } if (req.method != "GET" && req.method != "HEAD") { return (pass); } if (req.http.Authorization || req.http.Cookie) { return (pass); } return (hash); } Idempotence State Action Receive request

Slide 109

Slide 109 text

sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } return (lookup); } Lookup in cache Variations Action

Slide 110

Slide 110 text

sub vcl_purge { return (synth(200, "Purged")); } sub vcl_hit { if (obj.ttl >= 0s) { return (deliver); } if (obj.ttl + obj.grace > 0s) { return (deliver); } return (miss); } sub vcl_miss { return (fetch); } sub vcl_deliver { return (deliver); } Remove from cache Found in cache Not found in cache Return HTTP response to client

Slide 111

Slide 111 text

sub vcl_synth { set resp.http.Content-Type = "text/html; charset=utf-8"; set resp.http.Retry-After = "5"; synthetic( {" "} + resp.status + " " + resp.reason + {"

Error "} + resp.status + " " + resp.reason + {"

"} + resp.reason + {"

Guru Meditation:

XID: "} + req.xid + {"


Varnish cache server

"} ); return (deliver); } Send custom HTML

Slide 112

Slide 112 text

sub vcl_backend_fetch { return (fetch); } sub vcl_backend_response { if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Surrogate-control ~ "no-store" || (!beresp.http.Surrogate-Control && beresp.http.Cache-Control ~ "no-cache|no-store| private") || beresp.http.Vary == "*") { set beresp.ttl = 120s; set beresp.uncacheable = true; } return (deliver); } Send backend request Receive backend response TTL State

Slide 113

Slide 113 text

sub vcl_backend_error { set beresp.http.Content-Type = "text/html; charset=utf-8"; set beresp.http.Retry-After = "5"; synthetic( {" "} + beresp.status + " " + beresp.reason + {" title>

Error "} + beresp.status + " " + beresp.reason + {" h1>

"} + beresp.reason + {"

Guru Meditation:

XID: "} + bereq.xid + {"


Varnish cache server

"} ); return (deliver); } Send custom HTML on backend error

Slide 114

Slide 114 text

Minimal VCL

Slide 115

Slide 115 text

vcl 4.0; backend default { .host = "127.0.0.1"; .port = "8080"; } Minimal VCL

Slide 116

Slide 116 text

vcl 4.0; backend default { .host = "127.0.0.1"; .port = "80"; .max_connections = 300; .first_byte_timeout = 300s; .connect_timeout = 5s; .between_bytes_timeout = 2s; } More backend work

Slide 117

Slide 117 text

vcl 4.0; backend default { .host = "127.0.0.1"; .port = "80"; .max_connections = 300; .first_byte_timeout = 300s; .connect_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .url = "/"; .interval = 5s; .timeout = 1s; .window = 5; .threshold = 3; } } Even more backend work

Slide 118

Slide 118 text

vcl 4.0; backend default { .host = "127.0.0.1"; .port = "80"; .max_connections = 300; .first_byte_timeout = 300s; .connect_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .request = "HEAD / HTTP/1.1" "Host: localhost" "Connection: close" "User-Agent: Varnish Health Probe"; .interval = 5s; .timeout = 1s; .window = 5; .threshold = 3; } } Even more backend work

Slide 119

Slide 119 text

Load balancing

Slide 120

Slide 120 text

vcl 4.0; import directors; backend server1 { .host = “1.2.3.4”; .port = "80"; .max_connections = 300; .first_byte_timeout = 300s; .connect_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .request = "HEAD / HTTP/1.1" "Host: localhost" "Connection: close" "User-Agent: Varnish Health Probe"; .interval = 5s; .timeout = 1s; .window = 5; .threshold = 3; } } Loadbalancing: server 1

Slide 121

Slide 121 text

backend server2 { .host = “1.2.3.5”; .port = "80"; .max_connections = 300; .first_byte_timeout = 300s; .connect_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .request = "HEAD / HTTP/1.1" "Host: localhost" "Connection: close" "User-Agent: Varnish Health Probe"; .interval = 5s; .timeout = 1s; .window = 5; .threshold = 3; } } Loadbalancing: server 2

Slide 122

Slide 122 text

sub vcl_init { new vdir = directors.round_robin(); vdir.add_backend(server1); vdir.add_backend(server2); } sub vcl_recv { set req.backend_hint = vdir.backend(); } Loadbalancing: round robin

Slide 123

Slide 123 text

sub vcl_init { new vdir = directors.random(); vdir.add_backend(server1,2); vdir.add_backend(server2,3); } sub vcl_recv { set req.backend_hint = vdir.backend(); } Loadbalancing: random

Slide 124

Slide 124 text

sub vcl_init { new vdir = directors.fallback(); vdir.add_backend(server1); vdir.add_backend(server2); } sub vcl_recv { set req.backend_hint = vdir.backend(); } Loadbalancing: fallback

Slide 125

Slide 125 text

sub vcl_init { new vdir = directors.hash(); vdir.add_backend(server1); vdir.add_backend(server2); } sub vcl_recv { set req.backend_hint = vdir.backend(req.url); } Loadbalancing: URL hash

Slide 126

Slide 126 text

sub vcl_init { new vdir = directors.hash(); vdir.add_backend(server1); vdir.add_backend(server2); } sub vcl_recv { set req.backend_hint = vdir.backend(client.identity); } Loadbalancing: IP hash

Slide 127

Slide 127 text

sub vcl_recv { if(req.url ~ “^/products”) { set req.backend_hint = server1; } else { set req.backend_hint = server2; } } Conditional loadbalacning

Slide 128

Slide 128 text

Normalize

Slide 129

Slide 129 text

vcl 4.0; import std; sub vcl_recv { set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); set req.url = std.querysort(req.url); if (req.url ~ "\#") { set req.url = regsub(req.url, "\#.*$", ""); } if (req.url ~ "\?$") { set req.url = regsub(req.url, "\?$", ""); } if (req.restarts == 0) { if (req.http.Accept-Encoding) { if (req.http.User-Agent ~ "MSIE 6") { unset req.http.Accept-Encoding; } elsif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { unset req.http.Accept-Encoding; } } } } Normalize

Slide 130

Slide 130 text

Static assets

Slide 131

Slide 131 text

vcl 4.0; sub vcl_recv { if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac| flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf| ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf| txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { unset req.http.Cookie; return (hash); } } sub vcl_backend_response { if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac| flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf| ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf| txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { unset beresp.http.set-cookie; } if (bereq.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4| mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") { unset beresp.http.set-cookie; set beresp.do_stream = true; set beresp.do_gzip = false; } } Cache static assets

Slide 132

Slide 132 text

Do you really want to cache static assets?

Slide 133

Slide 133 text

Nginx or Apache can be fast enough for that

Slide 134

Slide 134 text

vcl 4.0; import std; sub vcl_recv { if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac| flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf| ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf| txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") { unset req.http.Cookie; return (pass); } } Don’t cache static assets

Slide 135

Slide 135 text

URL whitelist/blacklist

Slide 136

Slide 136 text

sub vcl_recv { if (req.url ~ "^/status\.php$" || req.url ~ "^/update\.php$" || req.url ~ "^/admin$" || req.url ~ "^/admin/.*$" || req.url ~ "^/user$" || req.url ~ "^/user/.*$" || req.url ~ "^/flag/.*$" || req.url ~ "^.*/ajax/.*$" || req.url ~ "^.*/ahah/.*$") { return (pass); } } URL blacklist

Slide 137

Slide 137 text

sub vcl_recv { if (req.url ~ "^/products/?" return (hash); } } URL whitelist

Slide 138

Slide 138 text

Those damn cookies again!

Slide 139

Slide 139 text

vcl 4.0; sub vcl_recv { set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "_gat=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", ""); set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", ""); if (req.http.cookie ~ "^\s*$") { unset req.http.cookie; } } Remove tracking cookies

Slide 140

Slide 140 text

vcl 4.0; sub vcl_recv { if (req.http.Cookie) { 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 ~ "^\s*$") { unset req.http.cookie; } } } Only keep session cookie

Slide 141

Slide 141 text

sub vcl_recv { if (req.http.Cookie) { set req.http.Cookie = ";" + req.http.Cookie; set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); set req.http.Cookie = regsuball(req.http.Cookie, ";(language)=", "; \1="); set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); if (req.http.cookie ~ "^\s*$") { unset req.http.cookie; return(pass); } return(hash); } } sub vcl_hash { hash_data(regsub( req.http.Cookie, "^.*language=([^;]*);*.*$", "\1" )); } Language cookie cache variation

Slide 142

Slide 142 text

Alternative language cache variation

Slide 143

Slide 143 text

sub vcl_hash { hash_data(req.http.Accept-Language); } Language cookie cache variation Or just send a “Vary:Accept-Language” header

Slide 144

Slide 144 text

sub vcl_hash { hash_data(req.http.Cookie); } Hash all cookies

Slide 145

Slide 145 text

Edge Side Includes

Slide 146

Slide 146 text

sub vcl_recv { set req.http.Surrogate-Capability = "key=ESI/1.0"; } sub vcl_backend_response { if (beresp.http.Surrogate-Control ~ "ESI/1.0") { unset beresp.http.Surrogate-Control; set beresp.do_esi = true; return(deliver); } } Edge Side Includes

Slide 147

Slide 147 text

'; '.PHP_EOL; echo "Date in the main page: ".date('Y-m-d H:i:s').'
'; Main page ESI frame: esi.php Cached for 10 seconds Not cached

Slide 148

Slide 148 text

ESI_xmlerror No ESI processing, first char not '<'. (See feature esi_disable_xml_check) Expects HTML/ XML tags

Slide 149

Slide 149 text

-p feature=+esi_disable_xml_check Add as startup option

Slide 150

Slide 150 text

Control Time To Live

Slide 151

Slide 151 text

sub vcl_backend_response { set beresp.ttl = 3h; } Control Time To Live

Slide 152

Slide 152 text

sub vcl_backend_response { if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") { set beresp.ttl = 120s; set beresp.uncacheable = true; return (deliver); } } Control Time To Live

Slide 153

Slide 153 text

Debugging

Slide 154

Slide 154 text

sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } } Debugging

Slide 155

Slide 155 text

Anonymize

Slide 156

Slide 156 text

sub vcl_deliver { unset resp.http.X-Powered-By; unset resp.http.Server; unset resp.http.X-Drupal-Cache; unset resp.http.X-Varnish; unset resp.http.Via; unset resp.http.Link; unset resp.http.X-Generator; } Anonymize

Slide 157

Slide 157 text

Purging

Slide 158

Slide 158 text

acl purge { "localhost"; "127.0.0.1"; "::1"; } sub vcl_recv { if (req.method == "PURGE") { if (!client.ip ~ purge) { return (synth(405, “Not allowed.”)); } return (purge); } } Purging

Slide 159

Slide 159 text

acl purge { "localhost"; "127.0.0.1"; "::1"; } sub vcl_backend_response { set beresp.http.x-url = bereq.url; set beresp.http.x-host = bereq.http.host; } sub vcl_deliver { unset resp.http.x-url; unset resp.http.x-host; } sub vcl_recv { if (req.method == "PURGE") { if (!client.ip ~ purge) { return (synth(405, "Not allowed")); } if(req.http.x-purge-regex) { ban("obj.http.x-host == " + req.http.host + " && obj.http.x-url ~ " + req.http.x-purge-regex); } else { ban("obj.http.x-host == " + req.http.host + " && obj.http.x-url == " + req.url); } return (synth(200, "Purged")); } } Banning

Slide 160

Slide 160 text

Banning curl -XPURGE -H "x-purge-regex:/products" "http://example.com" curl -XPURGE "http://example.com/products"

Slide 161

Slide 161 text

Banning through Varnishadm

Slide 162

Slide 162 text

varnishadm> ban obj.http.x-host == varnishtraining.dev && obj.http.x-url ~ /exercises/8 Varnishadm banning

Slide 163

Slide 163 text

varnishtop varnishtop -i ReqURL varnishtop -c -i VCL_call varnishtop -b -i VCL_call varnishtop -i ReqUrl -q "VCL_call eq 'HIT'" varnishtop -I VCL_call:PASS -I VCL_call:MISS -i ReqUrl -q "VCL_call eq 'MISS' or VCL_call eq 'PASS'" varnishtop -i ReqUrl -q "Timestamp:Process[2] > 0.8 Varnishtop filtering

Slide 164

Slide 164 text

Header-based invalidation

Slide 165

Slide 165 text

Header-based invalidation If-Modified-Since: Tue, 14 Jun 2016 11:49:18 GMT Last-Modified: Tue, 14 Jun 2016 11:49:32 GMT Cache-Control: max-age=10 HTTP 200: OK HTTP 304: Not modified

Slide 166

Slide 166 text

Header-based invalidation If-None-Match: 57601698ae1e2 Etag: 57601698ae1e2 Cache-Control: max-age=10 HTTP 200: OK HTTP 304: Not modified

Slide 167

Slide 167 text

beresp.keep Keep serving stale object while conditional backend request happens

Slide 168

Slide 168 text

Grace mode

Slide 169

Slide 169 text

beresp.grace Keep servering stale object while fetching data from backend Avoid excessive request queueing

Slide 170

Slide 170 text

sub vcl_backend_response { set beresp.grace = 6h; } Grace mode Monitoring & logging

Slide 171

Slide 171 text

Varnishstat Realtime statistics

Slide 172

Slide 172 text

No content

Slide 173

Slide 173 text

usage: varnishstat [-1lV] [-f field] [-t seconds|] [-n varnish_name] [-N filename] -1 # Print the statistics to stdout. -f field # Field inclusion glob # If it starts with '^' it is used as an exclusion list. -l # Lists the available fields to use with the -f option. -n varnish_name # The varnishd instance to get logs from. -N filename # Filename of a stale VSM instance. -t seconds| # Timeout before returning error on initial VSM connection. -V # Display the version number and exit. -x # Print statistics to stdout as XML. -j # Print statistics to stdout as JSON. Varnishstat usage

Slide 174

Slide 174 text

~# varnishstat -f MAIN.cache_hit -1 MAIN.cache_hit 13049135 5.39 Cache hits Varnishstat usage ~# varnishstat -f MAIN.cache_hit -j -1 { "timestamp": "2016-06-14T16:10:32", "MAIN.cache_hit": { "description": "Cache hits", "type": "MAIN", "flag": "c", "format": "i", "value": 13050992 } }

Slide 175

Slide 175 text

Varnishstat usage ~# varnishstat -f MAIN.n_object -f MAIN.n_lru_nuked -j { "timestamp": "2016-06-14T16:14:49", "MAIN.n_object": { "description": "object structs made", "type": "MAIN", "flag": "g", "format": "i", "value": 46295 }, "MAIN.n_lru_nuked": { "description": "Number of LRU nuked objects", "type": "MAIN", "flag": "g", "format": "i", "value": 0 } }

Slide 176

Slide 176 text

varnishstat -f MAIN.cache*

Slide 177

Slide 177 text

✓ Session ✓ Client ✓ Uptime ✓ Hit/miss ✓ Backend ✓ Fetch ✓ Threading ✓ Cache objects ✓ Memory ✓ Invalidation Varnishstat counters

Slide 178

Slide 178 text

Varnishlog In-memory logs of Varnish activity

Slide 179

Slide 179 text

* << Request >> 2 - Begin req 1 rxreq - Timestamp Start: 1466002470.571781 0.000000 0.000000 - Timestamp Req: 1466002470.571781 0.000000 0.000000 - ReqStart 10.10.10.1 51519 - ReqMethod GET - ReqURL /exercises/1/max.php - ReqProtocol HTTP/1.1 - ReqHeader Host: varnishtraining.dev - ReqHeader Connection: keep-alive - ReqHeader Upgrade-Insecure-Requests: 1 - ReqHeader User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 - ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - ReqHeader Accept-Encoding: gzip, deflate, sdch - ReqHeader Accept-Language: nl,en-US;q=0.8,en;q=0.6 - ReqHeader X-Forwarded-For: 10.10.10.1 - VCL_call RECV - VCL_return hash - ReqUnset Accept-Encoding: gzip, deflate, sdch - ReqHeader Accept-Encoding: gzip - VCL_call HASH - VCL_return lookup - VCL_call MISS - VCL_return fetch - Link bereq 3 fetch - Timestamp Fetch: 1466002470.574188 0.002407 0.002407 - RespProtocol HTTP/1.1 - RespStatus 200 - RespReason OK - RespHeader Server: nginx/1.10.1 - RespHeader Date: Wed, 15 Jun 2016 14:54:30 GMT - RespHeader Content-Type: text/html; charset=UTF-8 - RespHeader Cache-Control: max-age= 10 - RespHeader X-Varnish: 2 - RespHeader Age: 0 - RespHeader Via: 1.1 varnish-v4 - VCL_call DELIVER - VCL_return deliver - Timestamp Process: 1466002470.574226 0.002445 0.000038 - RespHeader Accept-Ranges: bytes - RespHeader Content-Length: 106 - Debug "RES_MODE 2" - RespHeader Connection: keep-alive - Timestamp Resp: 1466002470.574287 0.002507 0.000061 - ReqAcct 416 0 416 256 106 362 - End Client info: a MISS

Slide 180

Slide 180 text

* << BeReq >> 3 - Begin bereq 2 fetch - Timestamp Start: 1466002470.571910 0.000000 0.000000 - BereqMethod GET - BereqURL /exercises/1/max.php - BereqProtocol HTTP/1.1 - BereqHeader Host: varnishtraining.dev - BereqHeader Upgrade-Insecure-Requests: 1 - BereqHeader User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 - BereqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - BereqHeader Accept-Language: nl,en-US;q=0.8,en;q=0.6 - BereqHeader X-Forwarded-For: 10.10.10.1 - BereqHeader Accept-Encoding: gzip - BereqHeader X-Varnish: 3 - VCL_call BACKEND_FETCH - VCL_return fetch - BackendOpen 25 boot.default 127.0.0.1 8080 127.0.0.1 35536 - Timestamp Bereq: 1466002470.571998 0.000088 0.000088 - Timestamp Beresp: 1466002470.574088 0.002178 0.002090 - BerespProtocol HTTP/1.1 - BerespStatus 200 - BerespReason OK - BerespHeader Server: nginx/1.10.1 - BerespHeader Date: Wed, 15 Jun 2016 14:54:30 GMT - BerespHeader Content-Type: text/html; charset=UTF-8 - BerespHeader Transfer-Encoding: chunked - BerespHeader Connection: keep-alive - BerespHeader Cache-Control: max-age= 10 - TTL RFC 10 10 -1 1466002471 1466002471 1466002470 0 10 - VCL_call BACKEND_RESPONSE - VCL_return deliver - Storage malloc s0 - ObjProtocol HTTP/1.1 - ObjStatus 200 - ObjReason OK - ObjHeader Server: nginx/1.10.1 - ObjHeader Date: Wed, 15 Jun 2016 14:54:30 GMT - ObjHeader Content-Type: text/html; charset=UTF-8 - ObjHeader Cache-Control: max-age= 10 - Fetch_Body 2 chunked stream - BackendReuse 25 boot.default - Timestamp BerespBody: 1466002470.574162 0.002252 0.000073 - Length 106 - BereqAcct 420 0 420 198 106 304 - End Backend info: fetching

Slide 181

Slide 181 text

* << Request >> 7 - Begin req 4 rxreq - Timestamp Start: 1466002762.802285 0.000000 0.000000 - Timestamp Req: 1466002762.802285 0.000000 0.000000 - ReqStart 10.10.10.1 51560 - ReqMethod GET - ReqURL /exercises/1/max.php - ReqProtocol HTTP/1.1 - ReqHeader Host: varnishtraining.dev - ReqHeader Connection: keep-alive - ReqHeader Cache-Control: max-age=0 - ReqHeader Upgrade-Insecure-Requests: 1 - ReqHeader User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 - ReqHeader Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 - ReqHeader Accept-Encoding: gzip, deflate, sdch - ReqHeader Accept-Language: nl,en-US;q=0.8,en;q=0.6 - ReqHeader X-Forwarded-For: 10.10.10.1 - VCL_call RECV - VCL_return hash - ReqUnset Accept-Encoding: gzip, deflate, sdch - ReqHeader Accept-Encoding: gzip - VCL_call HASH - VCL_return lookup - Hit 6 - VCL_call HIT - VCL_return deliver - RespProtocol HTTP/1.1 - RespStatus 200 - RespReason OK - RespHeader Server: nginx/1.10.1 - RespHeader Date: Wed, 15 Jun 2016 14:59:21 GMT - RespHeader Content-Type: text/html; charset=UTF-8 - RespHeader Cache-Control: max-age= 10 - RespHeader X-Varnish: 7 6 - RespHeader Age: 1 - RespHeader Via: 1.1 varnish-v4 - VCL_call DELIVER - VCL_return deliver - Timestamp Process: 1466002762.802336 0.000051 0.000051 - RespHeader Accept-Ranges: bytes - RespHeader Content-Length: 106 - Debug "RES_MODE 2" - RespHeader Connection: keep-alive - Timestamp Resp: 1466002762.802414 0.000129 0.000078 - ReqAcct 442 0 442 258 106 364 - End Client info: a HIT

Slide 182

Slide 182 text

varnishlog varnishlog -i ReqURL varnishlog -g raw -i ReqURL varnishlog -g request -i ReqURL -i ReqHeader varnishlog -c varnishlog -b varnishlog -i ReqUrl -q "VCL_call eq 'HIT'" varnishlog -I VCL_call:PASS -I VCL_call:MISS -i ReqUrl -q "VCL_call eq 'MISS' or VCL_call eq 'PASS'" varnishlog -i ReqUrl -q "Timestamp:Process[2] > 0.8 Varnishlog filtering

Slide 183

Slide 183 text

Varnishtop Incremental in-memory Varnish logs

Slide 184

Slide 184 text

varnishtop varnishtop -i ReqURL varnishtop -c -i VCL_call varnishtop -b -i VCL_call varnishtop -i ReqUrl -q "VCL_call eq 'HIT'" varnishtop -I VCL_call:PASS -I VCL_call:MISS -i ReqUrl -q "VCL_call eq 'MISS' or VCL_call eq 'PASS'" varnishtop -i ReqUrl -q "Timestamp:Process[2] > 0.8 Varnishtop filtering

Slide 185

Slide 185 text

No content

Slide 186

Slide 186 text

VCL & ban module

Slide 187

Slide 187 text

No content