Slow websites
SUCK
HI, I'M THIJS
I'M THE TECH EVANGELIST
AT VARNISH SOFTWARE
WE BUILD SOFTWARE-DEFINED
WEB ACCELERATION & CONTENT
DELIVERY SOLUTIONS
MAGENTO
USER
UNDER PRESSURE
MAGENTO
USER VARNISH MAGENTO
VARNISH CONFIGURATION LANGUAGE
# VCL version 5.0 is not supported so it should be 4.0 even though actually used
Varnish version is 6
vcl 4.0;
import std;
# The minimal Varnish version is 6.0
# For SSL offloading, pass the following header in your proxy server or load
balancer: 'X-Forwarded-Proto: https'
backend default {
.host = "localhost";
.port = "8080";
.first_byte_timeout = 600s;
.probe = {
.url = "/health_check.php";
.timeout = 2s;
.interval = 5s;
.window = 10;
.threshold = 5;
}
}
acl purge {
"localhost";
}
sub vcl_recv {
if (req.restarts > 0) {
set req.hash_always_miss = true;
}
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
# To use the X-Pool header for purging varnish during automated
deployments, make sure the X-Pool header
# has been added to the response in your backend server config. This is
used, for example, by the
# capistrano-magento2 gem for purging old content from varnish during it's
deploy routine.
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header
required"));
}
if (req.http.X-Magento-Tags-Pattern) {
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
}
if (req.http.X-Pool) {
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
}
return (synth(200, "Purged"));
}
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# We only deal with GET and HEAD by default
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Bypass customer, shopping cart, checkout
if (req.url ~ "/customer" || req.url ~ "/checkout") {
return (pass);
}
# Bypass health check requests
if (req.url ~ "^/(pub/)?(health_check.php)$") {
return (pass);
}
# Set initial grace period usage status
set req.http.grace = "none";
# normalize url in case of leading HTTP scheme and domain
set req.url = regsub(req.url, "^http[s]?://", "");
# collect all cookies
std.collect(req.http.Cookie);
# Remove all marketing get parameters to minimize the cache objects
if (req.url ~ "(?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|
utm_[a-z]+|_bta_[a-z]+)=") {
set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|
fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
set req.url = regsub(req.url, "[?|&]+$", "");
}
# Static files caching
if (req.url ~ "^/(pub/)?(media|static)/") {
# Static files should not be cached by default
return (pass);
# But if you use a few locales and don't use CDN you can enable caching
static files by commenting previous line (#return (pass);) and uncommenting next 3
lines
#unset req.http.Https;
#unset req.http.X-Forwarded-Proto;
#unset req.http.Cookie;
}
# Bypass authenticated GraphQL requests without a X-Magento-Cache-Id
if (req.url ~ "/graphql" && !req.http.X-Magento-Cache-Id &&
req.http.Authorization ~ "^Bearer") {
return (pass);
}
return (hash);
}
sub vcl_hash {
if ((req.url !~ "/graphql" || !req.http.X-Magento-Cache-Id) && req.http.cookie
~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$",
"1"));
}
# To make sure http users don't see ssl warning
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
if (req.url ~ "/graphql") {
call process_graphql_headers;
}
}
sub process_graphql_headers {
if (req.http.X-Magento-Cache-Id) {
hash_data(req.http.X-Magento-Cache-Id);
# When the frontend stops sending the auth token, make sure users stop
getting results cached for logged-in users
if (req.http.Authorization ~ "^Bearer") {
hash_data("Authorized");
}
}
if (req.http.Store) {
hash_data(req.http.Store);
}
if (req.http.Content-Currency) {
hash_data(req.http.Content-Currency);
}
}
sub vcl_backend_response {
set beresp.grace = 3d;
if (beresp.http.content-type ~ "text") {
set beresp.do_esi = true;
}
if (bereq.url ~ ".js$" || beresp.http.content-type ~ "text") {
set beresp.do_gzip = true;
}
if (beresp.http.X-Magento-Debug) {
set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control;
}
# cache only successfully responses and 404s that are not marked as private
if ((beresp.status != 200 && beresp.status != 404) || beresp.http.Cache-
Control ~ "private") {
set beresp.uncacheable = true;
set beresp.ttl = 86400s;
return (deliver);
}
# validate if we need to cache it and prevent from setting cookie
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
# Collapse beresp.http.set-cookie in order to merge multiple set-cookie
headers
# Although it is not recommended to collapse set-cookie header,
# it is safe to do it here as the set-cookie header is removed below
std.collect(beresp.http.set-cookie);
# Do not cache the response under current cache key (hash),
# if the response has X-Magento-Vary but the request does not.
if ((bereq.url !~ "/graphql" || !bereq.http.X-Magento-Cache-Id)
&& bereq.http.cookie !~ "X-Magento-Vary="
&& beresp.http.set-cookie ~ "X-Magento-Vary=") {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
}
unset beresp.http.set-cookie;
}
# If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass
if (beresp.ttl <= 0s ||
beresp.http.Surrogate-control ~ "no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "no-cache|no-store") ||
beresp.http.Vary == "*") {
# Mark as Hit-For-Pass for the next 2 minutes
set beresp.ttl = 120s;
set beresp.uncacheable = true;
}
# If the cache key in the Magento response doesn't match the one that was sent
in the request, don't cache under the request's key
if (bereq.url ~ "/graphql" && bereq.http.X-Magento-Cache-Id && bereq.http.X-
Magento-Cache-Id != beresp.http.X-Magento-Cache-Id) {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
}
return (deliver);
}
sub vcl_deliver {
if (obj.uncacheable) {
set resp.http.X-Magento-Cache-Debug = "UNCACHEABLE";
} else if (obj.hits) {
set resp.http.X-Magento-Cache-Debug = "HIT";
set resp.http.Grace = req.http.grace;
} else {
set resp.http.X-Magento-Cache-Debug = "MISS";
}
# Not letting browser to cache non-static files.
if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|
static)/") {
set resp.http.Pragma = "no-cache";
set resp.http.Expires = "-1";
set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-
A LOT OF VCL CODE
NO NEED TO
CONFIGURE OR
EXPORT
sub vcl_recv {
# Set initial grace period usage status
set req.http.grace = "none";
# normalize url in case of leading HTTP scheme and domain
set req.url = regsub(req.url, "^http[s]?://", "");
# Static files caching
if (req.url ~ "^/(pub/)?(media|static)/") {
# Static files should not be cached by default
return (pass);
}
}
THINGS THAT DON'T MAKE SENSE
sub vcl_backend_response {
set beresp.grace = 3d;
# cache only successfully responses and 404s that are not marked as private
if ((beresp.status != 200 && beresp.status != 404) || beresp.http.Cache-Control ~ "private") {
set beresp.uncacheable = true;
set beresp.ttl = 86400s;
return (deliver);
}
}
THINGS THAT DON'T MAKE SENSE
OBJECT LIFETIME = TTL + GRACE + KEEP
OBJECT LIFETIME = TTL + GRACE + KEEP
DEFAULT:
120S
OBJECT LIFETIME = TTL + GRACE + KEEP
DEFAULT:
10S
SERVE STALE
CONTENT, ASYNC
REVALIDATION
OBJECT LIFETIME = TTL + GRACE + KEEP
DEFAULT:
0S
KEEP OBJECT
AROUND,
SYNCHRONOUS
REVALIDATION
HIGH GRACE OR KEEP HAS MEMORY IMPACT
LRU EVICTION WILL KICK IN
THINGS THAT DON'T MAKE SENSE
sub vcl_hit {
if (obj.ttl >= 0s) {
# Hit within TTL period
return (deliver);
}
if (std.healthy(req.backend_hint)) {
if (obj.ttl + 300s > 0s) {
# Hit after TTL expiration, but within grace period
set req.http.grace = "normal (healthy server)";
return (deliver);
} else {
# Hit after TTL and grace expiration
return (restart);
}
} else {
# server is not healthy, retrieve from cache
set req.http.grace = "unlimited (unhealthy server)";
return (deliver);
}
}
OBSTACLES &LIMITATIONS
COMMON OBSTACLES
✓ TLS HANDLING
✓ BACKEND ISSUES
✓ CACHE INVALIDATION & SOFT PURGES
✓ STORAGE & MEMORY MANAGEMENT
✓ UNDERSTANDING VCL & DEBUGGING
https://www.varnish-software.com/developers/tutorials/con
fi
guring-varnish-magento/
WE'RE
TACKLING SOME OF
THESE LIMITATIONS IN OUR
COMMERCIAL OFFERING
End-to-end TLS support
Client-side & backend TLS support
DELIVERY &
COURIER SERVICES
NEED TO SEND SOMETHING?
WE OFFER
Tag-based cache invalidation
Invalidate multiple objects based on user-
defined tags. Outperforms Varnish bans
and is fully compatible with Magento
Advanced header, cookie &
URL processing
A collection of VMODs that give you the
ability to manage cookies, headers and
URLs using a clean API, without the messy
regular expressions
Optimized Varnish Enterprise for
Magento VCL file
A VCL file that is optimized for Magento
and that uses the Varnish Enterprise for
Magento feature set
Memory Governor
Dynamically scale the size of the cache
based on worker process memory
requirements. Prevents Out-Of-Memory
issues at scale
Dynamic backends
Dynamic DNS resolution of backend
hostnames, supporting DNS changes at
runtime and DNS-based load balancing
Rate limiting &
bandwidth throttling
Scan here
for details
Enforce rate limiting of user requests
and throttle bandwidth based on user-
defined criteria
Meet Magento Poland attendees can take advantage of an exclusive offer to
upgrade to Varnish Enterprise for Magento at a reduced price.
This version of Varnish is packaged with select enterprise features that will
further enhance the caching of Magento.
The packaged features include:
SELECT VARNISH ENTERPRISE FEATURES,
OPTIMIZED AND PACKAGED FOR MAGENTO
REGISTER YOUR INTEREST
EXCLUSIVELY FOR MEET MAGENTO POLAND
ATTENDEES, LIMITED AVAILABILITY, REDUCED PRICE
TERMS & CONDITIONS APPLY*
VARNISH
ENTERPRISE
FOR MAGENTO
EXCLUSIVE OFFER:
✓ EXCLUSIVE OFFER
ONLY FOR MEET MAGENTO POLAND
ATTENDEES
✓ VARNISH ENTERPRISE CORE +
SELECT ENTERPRISE FEATURES &
MODULES
✓ REDUCED PRICE
✓ OPTIMIZED FOR MAGENTO
V
I
S
I
T
O
U
R
B
O
O
T
H
HITCH
TLS HANDLING
USER VARNISH MAGENTO
NATIVE TLS IN VARNISH ENTERPRISE
80 & 443 80 & 443
BUILT TO GO BEYOND 150 GBPS
WE CAN HANDLE
1.5 TBPS NOW
frontend = {
host = "*"
port = "443"
}
pem-file = {
cert = "/etc/varnish/certs/my.crt"
private-key = "/etc/varnish/certs/my.key"
}
ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-
SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-
RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305"
tls-protos = TLSv1.2 TLSv1.3
ecdh-curve = "X25519:prime256v1:secp384r1"
prefer-server-ciphers = false
alpn-protos = "h2,http/1.1"
varnishd -f /etc/varnish/default.vcl -a :80 -A /etc/varnish/tls.cfg
TLS.CFG
varnishadm tls.cert.commit
varnishadm tls.cert.discard <cert-id>
varnishadm tls.cert.list [-s]
varnishadm tls.cert.load [cert-id] <filename> [-f frontend-name] [-k
private key filename] [-s cipher-suites] [-p protos] [-c ciphers] [-o]
[-d] [-i sni filter]
varnishadm tls.cert.reload
varnishadm tls.cert.rollback
varnishd -f /etc/varnish/default.vcl -a :80 -a :443,https
LOAD
CERTIFICATES IN ADMIN
CONSOLE
NATIVE TLS IN VARNISH ENTERPRISE
socket.close
start
tls.cert.load /etc/varnish/certs/mycert.pem
tls.cert.commit
socket.open
varnishd -f /etc/varnish/default.vcl -a :80 -a :443,https -I /etc/
varnish/cli.cfg
CLI.CFG
LOADED ON
STARTUP
NATIVE TLS IN VARNISH ENTERPRISE
backend default {
.host = "magento.example.com";
.port = "443";
.ssl = 1;
.ssl_sni = 1;
.ssl_verify_peer = 1;
.ssl_verify_host = 1;
.first_byte_timeout = 600s;
.probe = {
.url = "/health_check.php";
.timeout = 2s;
.interval = 5s;
.window = 10;
.threshold = 5;
}
}
BACKEND
TLS
THE PROBLEM
80 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
THE PROBLEM
70 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
✓ RUNTIME COST OF VARNISH
THE PROBLEM
65 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
✓ RUNTIME COST OF VARNISH
✓ TRANSIENT OBJECTS
5 GB FOR
TRANSIENT
THE PROBLEM
65 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
✓ RUNTIME COST OF VARNISH
✓ TRANSIENT OBJECTS
✓ VARYING TRAFFIC PATTERNS
5 GB FOR
TRANSIENT
65 GB FOR CACHED OBJECTS 90 GB
6 GB FOR
OBJECT
OVERHEAD
8 GB FOR
WORKSPACE
CLIENT
6 GB FOR
TRANSIENT
HIGH TRAFFIC
LOW TRAFFIC
THE PROBLEM
65 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
✓ RUNTIME COST OF VARNISH
✓ TRANSIENT OBJECTS
✓ VARYING TRAFFIC PATTERNS
✓ VCL MISTAKES
5 GB FOR
TRANSIENT
65 GB FOR CACHED OBJECTS
7 GB FOR
OBJECT
OVERHEAD
8 GB FOR
WORKSPACE
CLIENT
17 GB FOR TRANSIENT
HIGH TRAFFIC
LOW TRAFFIC
THE PROBLEM
65 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
✓ RUNTIME COST OF VARNISH
✓ TRANSIENT OBJECTS
✓ VARYING TRAFFIC PATTERNS
✓ VCL MISTAKES
5 GB FOR
TRANSIENT
65 GB FOR CACHED OBJECTS
7 GB FOR
OBJECT
OVERHEAD
8 GB FOR
WORKSPACE
CLIENT
17 GB FOR TRANSIENT
HIGH TRAFFIC
LOW TRAFFIC
FIXED AMOUNT VARIABLE AMOUNT
MEMORY GOVERNOR LIMITS THE
MEMORY SIZE OF THE VARNISH PROCESS
INSTEAD OF THE CACHE OBJECT SIZE
MEMORY GOVERNOR
70 GB FOR CACHED OBJECTS HEAD ROOM 90 GB
5 GB FOR
OBJECT
OVERHEAD
5 GB FOR
WORKSPACE
CLIENT
65 GB FOR CACHED OBJECTS
7 GB FOR
OBJECT
OVERHEAD
8 GB FOR
WORKSPACE
CLIENT
FIXED AMOUNT
HEAD ROOM
HIGH TRAFFIC
LOW TRAFFIC
VARIABLE AMOUNT
varnishd -s malloc mse
varnishd -s mse
varnishd -s mse -p memory_target=80%
varnishd -s mse -p memory_target=50G
TAG-BASED CACHE INVALIDATION
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
}
if (req.http.X-Magento-Tags-Pattern) {
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
}
if (req.http.X-Pool) {
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
}
return (synth(200, "Purged"));
}
}
CURRENT
IMPLEMENTATION
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required"));
}
if (req.http.X-Magento-Tags-Pattern) {
ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern);
}
if (req.http.X-Pool) {
ban("obj.http.X-Pool ~ " + req.http.X-Pool);
}
return (synth(200, "Purged"));
}
}
$ varnishadm ban.list
Present bans:
1727438962.423744 2 - obj.http.X-Magento-Tags ~ ((^|,)cat_p_1(,|$))
1727438962.414895 0 C obj.http.X-Magento-Tags ~ .*
1727273313.798067 1681 C
X-Magento-Tags:
store,cms_b,cms_b_1,cms_b_footer_links_block,cat_p_1,cat_p,cat_p_6,cat_p
_3,cat_p_4,cat_p_5,cat_p_7,cat_p_12,cat_p_14,cat_p_13,review_block
PURGE / HTTP/1.1
Host: localhost
X-Magento-Tags-Pattern: ((^|,)cat_p_1(,|$))
PURGE / HTTP/1.1
Host: localhost
X-Magento-Tags-Pattern: .*
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
LEVERAGES THE
YKEY VMOD
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
import ykey;
acl purge {
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Method not allowed"));
}
if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) {
return (purge);
}
if (req.http.X-Magento-Tags-Pattern) {
set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", "");
}
if (req.http.X-Pool) {
set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", "");
}
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " ");
set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all");
set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true);
return (synth(200, "Purged " + req.http.n-purged + " objects"));
}
}
sub vcl_backend_response {
ykey.add_header(beresp.http.X-Magento-Tags, sep=",");
ykey.add_header(beresp.http.X-Pool, sep=",");
ykey.add_key("all");
}
ykey.purge_header(HEADER hdr, ",", true);
SOFT PURGING
OBJECT LIFETIME = TTL + GRACE + KEEP
SOFT PURGE SETS
TTL TO ZERO & KEEPS
GRACE & KEEP VALUE
sub vcl_backend_response {
set beresp.grace = 3d;
}
HOW TO APPROACH GRACE?
MEMORY GOVERNOR
WILL CONTROL THE
IMPACT OF LONG GRACE
VALUES
SOFT
PURGES WILL
BENEFIT FROM
LONGER GRACE
sub vcl_recv {
if (std.healthy(req.backend_hint)) {
set req.grace = 300s;
}
}
sub vcl_backend_response {
set beresp.grace = 3d;
}
HOW TO APPROACH GRACE?
LOWER GRACE FOR
STALENESS, HIGHER
GRACE FOR ERRORS
backend default {
.host = "magento.example.com";
.port = "443";
.ssl = 1;
.ssl_sni = 1;
.ssl_verify_peer = 1;
.ssl_verify_host = 1;
.first_byte_timeout = 600s;
.probe = {
.url = "/health_check.php";
.timeout = 2s;
.interval = 5s;
.window = 10;
.threshold = 5;
}
}
DNS
RESOLUTION AT
COMPILE TIME
import activedns;
import udo;
backend default {
.host = "0.0.0.0";
.ssl = 1;
}
probe health {
.url = "/health_check.php";
}
sub vcl_init {
new group = activedns.dns_group("magento.example.com:443");
group.set_ttl_rule(force);
group.set_ttl(5s);
group.set_backend_template(default);
group.set_probe_template(health);
new magento = udo.director();
magento.set_type(random);
magento.subscribe(group.get_tag());
}
sub vcl_backend_fetch {
set bereq.backend = magento.backend();
}
sub vcl_backend_error {
return (retry);
}
import activedns;
import udo;
backend default {
.host = "0.0.0.0";
.ssl = 1;
}
probe health {
.url = "/health_check.php";
}
sub vcl_init {
new group = activedns.dns_group("magento.example.com:443");
group.set_ttl_rule(force);
group.set_ttl(5s);
group.set_backend_template(default);
group.set_probe_template(health);
new magento = udo.director();
magento.set_type(random);
magento.subscribe(group.get_tag());
}
sub vcl_backend_fetch {
set bereq.backend = magento.backend();
}
sub vcl_backend_error {
return (retry);
}
CONFIGURABLE
DNS RESOLUTION
SUPPORTS SRV,
A & AAAA
import activedns;
import udo;
backend default {
.host = "0.0.0.0";
.ssl = 1;
}
probe health {
.url = "/health_check.php";
}
sub vcl_init {
new group = activedns.dns_group("magento.example.com:443");
group.set_ttl_rule(force);
group.set_ttl(5s);
group.set_backend_template(default);
group.set_probe_template(health);
new magento = udo.director();
magento.set_type(random);
magento.subscribe(group.get_tag());
}
sub vcl_backend_fetch {
set bereq.backend = magento.backend();
}
sub vcl_backend_error {
return (retry);
}
DNS-BASED
LOADBALANCING
HASH, FALLBACK OR
RANDOM DISTRIBUTION
import activedns;
import udo;
backend default {
.host = "0.0.0.0";
.ssl = 1;
}
probe health {
.url = "/health_check.php";
}
sub vcl_init {
new group = activedns.dns_group("magento.example.com:443");
group.set_ttl_rule(force);
group.set_ttl(5s);
group.set_backend_template(default);
group.set_probe_template(health);
new magento = udo.director();
magento.set_type(random);
magento.subscribe(group.get_tag());
}
sub vcl_backend_fetch {
set bereq.backend = magento.backend();
}
sub vcl_backend_error {
return (retry);
}
DYNAMIC
BACKENDS
import activedns;
import udo;
backend default {
.host = "0.0.0.0";
.ssl = 1;
}
probe health {
.url = "/health_check.php";
}
sub vcl_init {
new group = activedns.dns_group("magento.example.com:443");
group.set_ttl_rule(force);
group.set_ttl(5s);
group.set_backend_template(default);
group.set_probe_template(health);
new magento = udo.director();
magento.set_type(random);
magento.subscribe(group.get_tag());
}
sub vcl_backend_fetch {
set bereq.backend = magento.backend();
}
sub vcl_backend_error {
return (retry);
}
RETRY OTHER
BACKEND IF MULTIPLE
BACKENDS ARE
RESOLVED
OPTIMIZED MAGENTO VCL WITH
ENTERPRISE FEATURES
End-to-end TLS support
Client-side & backend TLS support
DELIVERY &
COURIER SERVICES
NEED TO SEND SOMETHING?
WE OFFER
Tag-based cache invalidation
Invalidate multiple objects based on user-
defined tags. Outperforms Varnish bans
and is fully compatible with Magento
Advanced header, cookie &
URL processing
A collection of VMODs that give you the
ability to manage cookies, headers and
URLs using a clean API, without the messy
regular expressions
Optimized Varnish Enterprise for
Magento VCL file
A VCL file that is optimized for Magento
and that uses the Varnish Enterprise for
Magento feature set
Memory Governor
Dynamically scale the size of the cache
based on worker process memory
requirements. Prevents Out-Of-Memory
issues at scale
Dynamic backends
Dynamic DNS resolution of backend
hostnames, supporting DNS changes at
runtime and DNS-based load balancing
Rate limiting &
bandwidth throttling
Scan here
for details
Enforce rate limiting of user requests
and throttle bandwidth based on user-
defined criteria
Meet Magento Poland attendees can take advantage of an exclusive offer to
upgrade to Varnish Enterprise for Magento at a reduced price.
This version of Varnish is packaged with select enterprise features that will
further enhance the caching of Magento.
The packaged features include:
SELECT VARNISH ENTERPRISE FEATURES,
OPTIMIZED AND PACKAGED FOR MAGENTO
REGISTER YOUR INTEREST
EXCLUSIVELY FOR MEET MAGENTO POLAND
ATTENDEES, LIMITED AVAILABILITY, REDUCED PRICE
TERMS & CONDITIONS APPLY*
VARNISH
ENTERPRISE
FOR MAGENTO
EXCLUSIVE OFFER:
V
I
S
I
T
O
U
R
B
O
O
T
H
I STILL
OWE YOU
A BOOK
Varnish Enterprise - when you need the full power of caching

Varnish Enterprise - when you need the full power of caching

  • 2.
  • 3.
  • 4.
    I'M THE TECHEVANGELIST AT VARNISH SOFTWARE
  • 8.
    WE BUILD SOFTWARE-DEFINED WEBACCELERATION & CONTENT DELIVERY SOLUTIONS
  • 10.
  • 11.
  • 12.
  • 13.
  • 15.
    # VCL version5.0 is not supported so it should be 4.0 even though actually used Varnish version is 6 vcl 4.0; import std; # The minimal Varnish version is 6.0 # For SSL offloading, pass the following header in your proxy server or load balancer: 'X-Forwarded-Proto: https' backend default { .host = "localhost"; .port = "8080"; .first_byte_timeout = 600s; .probe = { .url = "/health_check.php"; .timeout = 2s; .interval = 5s; .window = 10; .threshold = 5; } } acl purge { "localhost"; } sub vcl_recv { if (req.restarts > 0) { set req.hash_always_miss = true; } if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } # To use the X-Pool header for purging varnish during automated deployments, make sure the X-Pool header # has been added to the response in your backend server config. This is used, for example, by the # capistrano-magento2 gem for purging old content from varnish during it's deploy routine. if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required")); } if (req.http.X-Magento-Tags-Pattern) { ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); } if (req.http.X-Pool) { ban("obj.http.X-Pool ~ " + req.http.X-Pool); } return (synth(200, "Purged")); } if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } # We only deal with GET and HEAD by default if (req.method != "GET" && req.method != "HEAD") { return (pass); } # Bypass customer, shopping cart, checkout if (req.url ~ "/customer" || req.url ~ "/checkout") { return (pass); } # Bypass health check requests if (req.url ~ "^/(pub/)?(health_check.php)$") { return (pass); } # Set initial grace period usage status set req.http.grace = "none"; # normalize url in case of leading HTTP scheme and domain set req.url = regsub(req.url, "^http[s]?://", ""); # collect all cookies std.collect(req.http.Cookie); # Remove all marketing get parameters to minimize the cache objects if (req.url ~ "(?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+| utm_[a-z]+|_bta_[a-z]+)=") { set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin| fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", ""); set req.url = regsub(req.url, "[?|&]+$", ""); } # Static files caching if (req.url ~ "^/(pub/)?(media|static)/") { # Static files should not be cached by default return (pass); # But if you use a few locales and don't use CDN you can enable caching static files by commenting previous line (#return (pass);) and uncommenting next 3 lines #unset req.http.Https; #unset req.http.X-Forwarded-Proto; #unset req.http.Cookie; } # Bypass authenticated GraphQL requests without a X-Magento-Cache-Id if (req.url ~ "/graphql" && !req.http.X-Magento-Cache-Id && req.http.Authorization ~ "^Bearer") { return (pass); } return (hash); } sub vcl_hash { if ((req.url !~ "/graphql" || !req.http.X-Magento-Cache-Id) && req.http.cookie ~ "X-Magento-Vary=") { hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "1")); } # To make sure http users don't see ssl warning if (req.http.X-Forwarded-Proto) { hash_data(req.http.X-Forwarded-Proto); } if (req.url ~ "/graphql") { call process_graphql_headers; } } sub process_graphql_headers { if (req.http.X-Magento-Cache-Id) { hash_data(req.http.X-Magento-Cache-Id); # When the frontend stops sending the auth token, make sure users stop getting results cached for logged-in users if (req.http.Authorization ~ "^Bearer") { hash_data("Authorized"); } } if (req.http.Store) { hash_data(req.http.Store); } if (req.http.Content-Currency) { hash_data(req.http.Content-Currency); } } sub vcl_backend_response { set beresp.grace = 3d; if (beresp.http.content-type ~ "text") { set beresp.do_esi = true; } if (bereq.url ~ ".js$" || beresp.http.content-type ~ "text") { set beresp.do_gzip = true; } if (beresp.http.X-Magento-Debug) { set beresp.http.X-Magento-Cache-Control = beresp.http.Cache-Control; } # cache only successfully responses and 404s that are not marked as private if ((beresp.status != 200 && beresp.status != 404) || beresp.http.Cache- Control ~ "private") { set beresp.uncacheable = true; set beresp.ttl = 86400s; return (deliver); } # validate if we need to cache it and prevent from setting cookie if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) { # Collapse beresp.http.set-cookie in order to merge multiple set-cookie headers # Although it is not recommended to collapse set-cookie header, # it is safe to do it here as the set-cookie header is removed below std.collect(beresp.http.set-cookie); # Do not cache the response under current cache key (hash), # if the response has X-Magento-Vary but the request does not. if ((bereq.url !~ "/graphql" || !bereq.http.X-Magento-Cache-Id) && bereq.http.cookie !~ "X-Magento-Vary=" && beresp.http.set-cookie ~ "X-Magento-Vary=") { set beresp.ttl = 0s; set beresp.uncacheable = true; } unset beresp.http.set-cookie; } # If page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass if (beresp.ttl <= 0s || beresp.http.Surrogate-control ~ "no-store" || (!beresp.http.Surrogate-Control && beresp.http.Cache-Control ~ "no-cache|no-store") || beresp.http.Vary == "*") { # Mark as Hit-For-Pass for the next 2 minutes set beresp.ttl = 120s; set beresp.uncacheable = true; } # If the cache key in the Magento response doesn't match the one that was sent in the request, don't cache under the request's key if (bereq.url ~ "/graphql" && bereq.http.X-Magento-Cache-Id && bereq.http.X- Magento-Cache-Id != beresp.http.X-Magento-Cache-Id) { set beresp.ttl = 0s; set beresp.uncacheable = true; } return (deliver); } sub vcl_deliver { if (obj.uncacheable) { set resp.http.X-Magento-Cache-Debug = "UNCACHEABLE"; } else if (obj.hits) { set resp.http.X-Magento-Cache-Debug = "HIT"; set resp.http.Grace = req.http.grace; } else { set resp.http.X-Magento-Cache-Debug = "MISS"; } # Not letting browser to cache non-static files. if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media| static)/") { set resp.http.Pragma = "no-cache"; set resp.http.Expires = "-1"; set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max- A LOT OF VCL CODE
  • 17.
  • 18.
    sub vcl_recv { #Set initial grace period usage status set req.http.grace = "none"; # normalize url in case of leading HTTP scheme and domain set req.url = regsub(req.url, "^http[s]?://", ""); # Static files caching if (req.url ~ "^/(pub/)?(media|static)/") { # Static files should not be cached by default return (pass); } } THINGS THAT DON'T MAKE SENSE
  • 19.
    sub vcl_backend_response { setberesp.grace = 3d; # cache only successfully responses and 404s that are not marked as private if ((beresp.status != 200 && beresp.status != 404) || beresp.http.Cache-Control ~ "private") { set beresp.uncacheable = true; set beresp.ttl = 86400s; return (deliver); } } THINGS THAT DON'T MAKE SENSE
  • 20.
    OBJECT LIFETIME =TTL + GRACE + KEEP
  • 21.
    OBJECT LIFETIME =TTL + GRACE + KEEP DEFAULT: 120S
  • 22.
    OBJECT LIFETIME =TTL + GRACE + KEEP DEFAULT: 10S SERVE STALE CONTENT, ASYNC REVALIDATION
  • 23.
    OBJECT LIFETIME =TTL + GRACE + KEEP DEFAULT: 0S KEEP OBJECT AROUND, SYNCHRONOUS REVALIDATION
  • 24.
    HIGH GRACE ORKEEP HAS MEMORY IMPACT LRU EVICTION WILL KICK IN
  • 25.
    THINGS THAT DON'TMAKE SENSE sub vcl_hit { if (obj.ttl >= 0s) { # Hit within TTL period return (deliver); } if (std.healthy(req.backend_hint)) { if (obj.ttl + 300s > 0s) { # Hit after TTL expiration, but within grace period set req.http.grace = "normal (healthy server)"; return (deliver); } else { # Hit after TTL and grace expiration return (restart); } } else { # server is not healthy, retrieve from cache set req.http.grace = "unlimited (unhealthy server)"; return (deliver); } }
  • 26.
  • 27.
    COMMON OBSTACLES ✓ TLSHANDLING ✓ BACKEND ISSUES ✓ CACHE INVALIDATION & SOFT PURGES ✓ STORAGE & MEMORY MANAGEMENT ✓ UNDERSTANDING VCL & DEBUGGING
  • 28.
  • 29.
    WE'RE TACKLING SOME OF THESELIMITATIONS IN OUR COMMERCIAL OFFERING
  • 30.
    End-to-end TLS support Client-side& backend TLS support DELIVERY & COURIER SERVICES NEED TO SEND SOMETHING? WE OFFER Tag-based cache invalidation Invalidate multiple objects based on user- defined tags. Outperforms Varnish bans and is fully compatible with Magento Advanced header, cookie & URL processing A collection of VMODs that give you the ability to manage cookies, headers and URLs using a clean API, without the messy regular expressions Optimized Varnish Enterprise for Magento VCL file A VCL file that is optimized for Magento and that uses the Varnish Enterprise for Magento feature set Memory Governor Dynamically scale the size of the cache based on worker process memory requirements. Prevents Out-Of-Memory issues at scale Dynamic backends Dynamic DNS resolution of backend hostnames, supporting DNS changes at runtime and DNS-based load balancing Rate limiting & bandwidth throttling Scan here for details Enforce rate limiting of user requests and throttle bandwidth based on user- defined criteria Meet Magento Poland attendees can take advantage of an exclusive offer to upgrade to Varnish Enterprise for Magento at a reduced price. This version of Varnish is packaged with select enterprise features that will further enhance the caching of Magento. The packaged features include: SELECT VARNISH ENTERPRISE FEATURES, OPTIMIZED AND PACKAGED FOR MAGENTO REGISTER YOUR INTEREST EXCLUSIVELY FOR MEET MAGENTO POLAND ATTENDEES, LIMITED AVAILABILITY, REDUCED PRICE TERMS & CONDITIONS APPLY* VARNISH ENTERPRISE FOR MAGENTO EXCLUSIVE OFFER: ✓ EXCLUSIVE OFFER ONLY FOR MEET MAGENTO POLAND ATTENDEES ✓ VARNISH ENTERPRISE CORE + SELECT ENTERPRISE FEATURES & MODULES ✓ REDUCED PRICE ✓ OPTIMIZED FOR MAGENTO V I S I T O U R B O O T H
  • 31.
  • 32.
    USER VARNISH MAGENTO NATIVETLS IN VARNISH ENTERPRISE 80 & 443 80 & 443
  • 33.
    BUILT TO GOBEYOND 150 GBPS WE CAN HANDLE 1.5 TBPS NOW
  • 34.
    frontend = { host= "*" port = "443" } pem-file = { cert = "/etc/varnish/certs/my.crt" private-key = "/etc/varnish/certs/my.key" } ciphersuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM- SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE- RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305" tls-protos = TLSv1.2 TLSv1.3 ecdh-curve = "X25519:prime256v1:secp384r1" prefer-server-ciphers = false alpn-protos = "h2,http/1.1" varnishd -f /etc/varnish/default.vcl -a :80 -A /etc/varnish/tls.cfg TLS.CFG
  • 35.
    varnishadm tls.cert.commit varnishadm tls.cert.discard<cert-id> varnishadm tls.cert.list [-s] varnishadm tls.cert.load [cert-id] <filename> [-f frontend-name] [-k private key filename] [-s cipher-suites] [-p protos] [-c ciphers] [-o] [-d] [-i sni filter] varnishadm tls.cert.reload varnishadm tls.cert.rollback varnishd -f /etc/varnish/default.vcl -a :80 -a :443,https LOAD CERTIFICATES IN ADMIN CONSOLE NATIVE TLS IN VARNISH ENTERPRISE
  • 36.
    socket.close start tls.cert.load /etc/varnish/certs/mycert.pem tls.cert.commit socket.open varnishd -f/etc/varnish/default.vcl -a :80 -a :443,https -I /etc/ varnish/cli.cfg CLI.CFG LOADED ON STARTUP NATIVE TLS IN VARNISH ENTERPRISE
  • 37.
    backend default { .host= "magento.example.com"; .port = "443"; .ssl = 1; .ssl_sni = 1; .ssl_verify_peer = 1; .ssl_verify_host = 1; .first_byte_timeout = 600s; .probe = { .url = "/health_check.php"; .timeout = 2s; .interval = 5s; .window = 10; .threshold = 5; } } BACKEND TLS
  • 39.
    THE PROBLEM 80 GBFOR CACHED OBJECTS HEAD ROOM 90 GB
  • 40.
    THE PROBLEM 70 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT ✓ RUNTIME COST OF VARNISH
  • 41.
    THE PROBLEM 65 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT ✓ RUNTIME COST OF VARNISH ✓ TRANSIENT OBJECTS 5 GB FOR TRANSIENT
  • 42.
    THE PROBLEM 65 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT ✓ RUNTIME COST OF VARNISH ✓ TRANSIENT OBJECTS ✓ VARYING TRAFFIC PATTERNS 5 GB FOR TRANSIENT 65 GB FOR CACHED OBJECTS 90 GB 6 GB FOR OBJECT OVERHEAD 8 GB FOR WORKSPACE CLIENT 6 GB FOR TRANSIENT HIGH TRAFFIC LOW TRAFFIC
  • 43.
    THE PROBLEM 65 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT ✓ RUNTIME COST OF VARNISH ✓ TRANSIENT OBJECTS ✓ VARYING TRAFFIC PATTERNS ✓ VCL MISTAKES 5 GB FOR TRANSIENT 65 GB FOR CACHED OBJECTS 7 GB FOR OBJECT OVERHEAD 8 GB FOR WORKSPACE CLIENT 17 GB FOR TRANSIENT HIGH TRAFFIC LOW TRAFFIC
  • 44.
    THE PROBLEM 65 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT ✓ RUNTIME COST OF VARNISH ✓ TRANSIENT OBJECTS ✓ VARYING TRAFFIC PATTERNS ✓ VCL MISTAKES 5 GB FOR TRANSIENT 65 GB FOR CACHED OBJECTS 7 GB FOR OBJECT OVERHEAD 8 GB FOR WORKSPACE CLIENT 17 GB FOR TRANSIENT HIGH TRAFFIC LOW TRAFFIC FIXED AMOUNT VARIABLE AMOUNT
  • 45.
    MEMORY GOVERNOR LIMITSTHE MEMORY SIZE OF THE VARNISH PROCESS INSTEAD OF THE CACHE OBJECT SIZE
  • 46.
    MEMORY GOVERNOR 70 GBFOR CACHED OBJECTS HEAD ROOM 90 GB 5 GB FOR OBJECT OVERHEAD 5 GB FOR WORKSPACE CLIENT 65 GB FOR CACHED OBJECTS 7 GB FOR OBJECT OVERHEAD 8 GB FOR WORKSPACE CLIENT FIXED AMOUNT HEAD ROOM HIGH TRAFFIC LOW TRAFFIC VARIABLE AMOUNT
  • 47.
  • 48.
    varnishd -s mse varnishd-s mse -p memory_target=80% varnishd -s mse -p memory_target=50G
  • 49.
  • 50.
    acl purge { "localhost"; } subvcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required")); } if (req.http.X-Magento-Tags-Pattern) { ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); } if (req.http.X-Pool) { ban("obj.http.X-Pool ~ " + req.http.X-Pool); } return (synth(200, "Purged")); } } CURRENT IMPLEMENTATION
  • 51.
    acl purge { "localhost"; } subvcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (synth(400, "X-Magento-Tags-Pattern or X-Pool header required")); } if (req.http.X-Magento-Tags-Pattern) { ban("obj.http.X-Magento-Tags ~ " + req.http.X-Magento-Tags-Pattern); } if (req.http.X-Pool) { ban("obj.http.X-Pool ~ " + req.http.X-Pool); } return (synth(200, "Purged")); } }
  • 52.
    $ varnishadm ban.list Presentbans: 1727438962.423744 2 - obj.http.X-Magento-Tags ~ ((^|,)cat_p_1(,|$)) 1727438962.414895 0 C obj.http.X-Magento-Tags ~ .* 1727273313.798067 1681 C X-Magento-Tags: store,cms_b,cms_b_1,cms_b_footer_links_block,cat_p_1,cat_p,cat_p_6,cat_p _3,cat_p_4,cat_p_5,cat_p_7,cat_p_12,cat_p_14,cat_p_13,review_block PURGE / HTTP/1.1 Host: localhost X-Magento-Tags-Pattern: ((^|,)cat_p_1(,|$)) PURGE / HTTP/1.1 Host: localhost X-Magento-Tags-Pattern: .*
  • 53.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } } LEVERAGES THE YKEY VMOD
  • 54.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } }
  • 55.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } }
  • 56.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } }
  • 57.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } }
  • 58.
    import ykey; acl purge{ "localhost"; } sub vcl_recv { if (req.method == "PURGE") { if (client.ip !~ purge) { return (synth(405, "Method not allowed")); } if (!req.http.X-Magento-Tags-Pattern && !req.http.X-Pool) { return (purge); } if (req.http.X-Magento-Tags-Pattern) { set req.http.X-Key-Purge = regsuball(req.http.X-Magento-Tags-Pattern, "[()^$]", ""); } if (req.http.X-Pool) { set req.http.X-Key-Purge = regsuball(req.http.X-Pool, "[()^$]", ""); } set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, "[,|]", " "); set req.http.X-Key-Purge = regsuball(req.http.X-Key-Purge, ".*", "all"); set req.http.n-purged = ykey.purge_header(req.http.X-Key-Purge, ",", true); return (synth(200, "Purged " + req.http.n-purged + " objects")); } }
  • 59.
    sub vcl_backend_response { ykey.add_header(beresp.http.X-Magento-Tags,sep=","); ykey.add_header(beresp.http.X-Pool, sep=","); ykey.add_key("all"); }
  • 60.
  • 61.
    OBJECT LIFETIME =TTL + GRACE + KEEP SOFT PURGE SETS TTL TO ZERO & KEEPS GRACE & KEEP VALUE
  • 62.
    sub vcl_backend_response { setberesp.grace = 3d; } HOW TO APPROACH GRACE? MEMORY GOVERNOR WILL CONTROL THE IMPACT OF LONG GRACE VALUES SOFT PURGES WILL BENEFIT FROM LONGER GRACE
  • 63.
    sub vcl_recv { if(std.healthy(req.backend_hint)) { set req.grace = 300s; } } sub vcl_backend_response { set beresp.grace = 3d; } HOW TO APPROACH GRACE? LOWER GRACE FOR STALENESS, HIGHER GRACE FOR ERRORS
  • 64.
    backend default { .host= "magento.example.com"; .port = "443"; .ssl = 1; .ssl_sni = 1; .ssl_verify_peer = 1; .ssl_verify_host = 1; .first_byte_timeout = 600s; .probe = { .url = "/health_check.php"; .timeout = 2s; .interval = 5s; .window = 10; .threshold = 5; } } DNS RESOLUTION AT COMPILE TIME
  • 65.
    import activedns; import udo; backenddefault { .host = "0.0.0.0"; .ssl = 1; } probe health { .url = "/health_check.php"; } sub vcl_init { new group = activedns.dns_group("magento.example.com:443"); group.set_ttl_rule(force); group.set_ttl(5s); group.set_backend_template(default); group.set_probe_template(health); new magento = udo.director(); magento.set_type(random); magento.subscribe(group.get_tag()); } sub vcl_backend_fetch { set bereq.backend = magento.backend(); } sub vcl_backend_error { return (retry); }
  • 66.
    import activedns; import udo; backenddefault { .host = "0.0.0.0"; .ssl = 1; } probe health { .url = "/health_check.php"; } sub vcl_init { new group = activedns.dns_group("magento.example.com:443"); group.set_ttl_rule(force); group.set_ttl(5s); group.set_backend_template(default); group.set_probe_template(health); new magento = udo.director(); magento.set_type(random); magento.subscribe(group.get_tag()); } sub vcl_backend_fetch { set bereq.backend = magento.backend(); } sub vcl_backend_error { return (retry); } CONFIGURABLE DNS RESOLUTION SUPPORTS SRV, A & AAAA
  • 67.
    import activedns; import udo; backenddefault { .host = "0.0.0.0"; .ssl = 1; } probe health { .url = "/health_check.php"; } sub vcl_init { new group = activedns.dns_group("magento.example.com:443"); group.set_ttl_rule(force); group.set_ttl(5s); group.set_backend_template(default); group.set_probe_template(health); new magento = udo.director(); magento.set_type(random); magento.subscribe(group.get_tag()); } sub vcl_backend_fetch { set bereq.backend = magento.backend(); } sub vcl_backend_error { return (retry); } DNS-BASED LOADBALANCING HASH, FALLBACK OR RANDOM DISTRIBUTION
  • 68.
    import activedns; import udo; backenddefault { .host = "0.0.0.0"; .ssl = 1; } probe health { .url = "/health_check.php"; } sub vcl_init { new group = activedns.dns_group("magento.example.com:443"); group.set_ttl_rule(force); group.set_ttl(5s); group.set_backend_template(default); group.set_probe_template(health); new magento = udo.director(); magento.set_type(random); magento.subscribe(group.get_tag()); } sub vcl_backend_fetch { set bereq.backend = magento.backend(); } sub vcl_backend_error { return (retry); } DYNAMIC BACKENDS
  • 69.
    import activedns; import udo; backenddefault { .host = "0.0.0.0"; .ssl = 1; } probe health { .url = "/health_check.php"; } sub vcl_init { new group = activedns.dns_group("magento.example.com:443"); group.set_ttl_rule(force); group.set_ttl(5s); group.set_backend_template(default); group.set_probe_template(health); new magento = udo.director(); magento.set_type(random); magento.subscribe(group.get_tag()); } sub vcl_backend_fetch { set bereq.backend = magento.backend(); } sub vcl_backend_error { return (retry); } RETRY OTHER BACKEND IF MULTIPLE BACKENDS ARE RESOLVED
  • 70.
    OPTIMIZED MAGENTO VCLWITH ENTERPRISE FEATURES
  • 71.
    End-to-end TLS support Client-side& backend TLS support DELIVERY & COURIER SERVICES NEED TO SEND SOMETHING? WE OFFER Tag-based cache invalidation Invalidate multiple objects based on user- defined tags. Outperforms Varnish bans and is fully compatible with Magento Advanced header, cookie & URL processing A collection of VMODs that give you the ability to manage cookies, headers and URLs using a clean API, without the messy regular expressions Optimized Varnish Enterprise for Magento VCL file A VCL file that is optimized for Magento and that uses the Varnish Enterprise for Magento feature set Memory Governor Dynamically scale the size of the cache based on worker process memory requirements. Prevents Out-Of-Memory issues at scale Dynamic backends Dynamic DNS resolution of backend hostnames, supporting DNS changes at runtime and DNS-based load balancing Rate limiting & bandwidth throttling Scan here for details Enforce rate limiting of user requests and throttle bandwidth based on user- defined criteria Meet Magento Poland attendees can take advantage of an exclusive offer to upgrade to Varnish Enterprise for Magento at a reduced price. This version of Varnish is packaged with select enterprise features that will further enhance the caching of Magento. The packaged features include: SELECT VARNISH ENTERPRISE FEATURES, OPTIMIZED AND PACKAGED FOR MAGENTO REGISTER YOUR INTEREST EXCLUSIVELY FOR MEET MAGENTO POLAND ATTENDEES, LIMITED AVAILABILITY, REDUCED PRICE TERMS & CONDITIONS APPLY* VARNISH ENTERPRISE FOR MAGENTO EXCLUSIVE OFFER: V I S I T O U R B O O T H
  • 72.