This page concerns regular tasks to be perform on Varnish.
voir aussi VarnishGuide
Contents
- Good debugging tools
- Upgrades
- Tâches avancées
- Troubleshooting
- Testing and benchmarking
- References
Good debugging tools
Those are life savers:
trace requests only from one IP
- Varnish 3.x
varnishlog -c -m ReqStart:66.130.160.12
- Varnish 2.x
varnishlog -c -o SessionOpen 66.130.160.12
(Found that tip here) (Tip for varnish 3 found here)
trace backend requests from that IP
This makes it possible to see, for example, only requests that you're issuing (to make debugging easier):
varnishlog -b -q 'BeReqHeader ~ "X-Forwarded-For: 184.160.35.43"'
You can also complexify matching using the VSL query language.
See: https://varnish-cache.org/docs/6.0/reference/vsl.html#vsl-7
test VCL syntax
varnishd -C -f /etc/varnish/default.vcl
(Found that in http://aaronbonner.io/post/14125553826/testing-varnish-vcl-syntax)
Show requests grouped by host or URL pattern
This tool helps with grouping information from varnishlog and presents it in an easy format (still untested!):
https://github.com/xcir/varnishHostStat
Upgrades
Just apt-get install and fix the syntax errors you find. Look into site_cache/files in puppet for previous upgrades and upstream documentation.
Follow all of 3.0 upgrades (wheezy)
Follow all of 4.0 upgrades (jessie) However, the "upgrading" document is not super complete.. refer to the following links for additional info:
req.grace is gone (link dead -- varnish-cache.org is into burning old books ) -- this article is a bit confusing and has the objective of setting http headers to reflect grace status which we don't wanna do.. but it shows the default VCL code for vcl_hit that already handles grace. basically now you only need to set beresp.grace (and maybe beresp.ttl) in vcl_backend_response and magic ensues.
synthetic is now a function so you should use parentheses for arguments -- e.g. synthetic("blah")
no more ban_url("blah") -- replace with ban("req.url ~ blah")
a somewhat badly documented side-effect of changes to vcl_error that becomes vcl_backend_error: to set the Content-Type header, you should use: set beresp.http.Content-Type = "...";
Follow all of 5.0 upgrades (stretch) -- no big changes from 4.x VCLs, mostly added features.
Follow all of 6.0 upgrades (buster) -- @TODO@ : Check changes
Tâches avancées
avoir des stats de varnish par munin
On peut avoir des stats de varnish en utilisant les plugins de munin. On a ça de codé dans puppet.
include cache::varnish::munin
exemple: https://stats.koumbit.net/varnish-day.html
Adding a site to varnish, detailed configuration
Varnish configuration
If you need a special configuration, you add it to a domain-specific if clause. The VCL (Varnish Configuration Language) will then vary according to the site being optimised.
VCL for Pressflow
Pressflow is a distribution of Drupal with integrated performance, scalability, availability, and testing enhancements. As such, it allows caches such as Varnish to cache cacheable content very easily. We still need to modify the Varnish VCL to have this actually work properly. Our config is based on this configuration and is deployed by puppet on both servers.
By default, we apply the above configuration to all hosts, so we support Pressflow out of the box. -- TheAnarcat 2011-02-01 21:41:40
We also use ceres as a backend so if your site is in a pressflow platform on aegir, there should be no modification necessary on the varnish server(s).
VCL for basic Drupal
The following configuration will completely remove cookies from all requests in Varnish, which will break all dynamic functionality on the website (logins, etc) but yield major performance improvements. The idea here is that the "dynamic" website is edited on another domain that doesn't point to varnish.
sub vcl_recv { if (req.http.host ~ "^(.*\.)?example.net$") { set req.backend = example; remove req.http.Set-Cookie; remove req.http.cookie; lookup; } } sub vcl_fetch { if (req.http.host ~ "^(.*\.)?example.net$" && obj.http.Set-Cookie) { insert; } }
Advanced drupal (w/ x-forward-proto support)
sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Varnish-Cache = "HIT"; } else { set resp.http.X-Varnish-Cache = "MISS"; } } sub vcl_recv { // AegirVPS only. //set req.backend_hint = aegirvps.backend(); // configuration from https://wiki.fourkitchens.com/display/PF/Configure+Varnish+for+Pressflow 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); } if (req.method != "GET" && req.method != "HEAD") { /* We only deal with GET and HEAD by default */ return (pass); } if (req.http.Cookie) { // Remove has_js and Google Analytics cookies. set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|__utma_a2a|has_js)=[^;]*", ""); // more removal, from: https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies // remove other stats cookies set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *__utm.=[^;]+;? *", "\1"); # removes all cookies named __utm? (utma, utmb...) - tracking thing // Remove all cookies but sessions set req.http.Cookie = ";" + req.http.Cookie; set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-zA-Z0-9=]+)=", "; \1="); set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); // Remove a ";" prefix, if present. set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", ""); // Remove empty cookies. if (req.http.Cookie ~ "^\s*$") { unset req.http.Cookie; } } if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } // Skip the Varnish cache for install, update, and cron if (req.url ~ "install\.php|update\.php|cron\.php") { return (pass); } if (req.url ~ "x") { ban ("req.url ~ ."); return(synth(500, "the cache is now purged.")); } // Normalize the Accept-Encoding header // as per: http://varnish-cache.org/wiki/FAQ/Compression if (req.http.Accept-Encoding) { if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { # No point in compressing these unset req.http.Accept-Encoding; } elsif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } else { # Unknown or deflate algorithm unset req.http.Accept-Encoding; } } return (hash); } // configuration from https://wiki.fourkitchens.com/display/PF/Configure+Varnish+for+Pressflow sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } if (req.http.X-Forwarded-Proto ~ "https") { hash_data(req.http.X-Forwarded-Proto); } if (req.http.Cookie) { hash_data(req.http.Cookie); } return (lookup); } // Strip any cookies before an image/js/css is inserted into cache. // configuration from https://wiki.fourkitchens.com/display/PF/Configure+Varnish+for+Pressflow sub vcl_backend_response { if (bereq.url ~ "\.(png|gif|jpg|swf|css|js)$") { // For Varnish 2.1 or later, replace obj with beresp: unset beresp.http.set-cookie; } // Let's have a little grace set beresp.ttl = 10s; set beresp.grace = 1h; }
This should probably be updated with the information available here: http://varnish-cache.org/wiki/VarnishAndDrupal
Config côté Drupal
Dans local.settings.php
<?php global $conf; global $is_https; $conf['reverse_proxy'] = TRUE; $conf['reverse_proxy_addresses'] = array('199.58.80.104', '199.58.80.105', '127.0.0.1'); $conf['reverse_proxy_header'] = 'HTTP_X_FORWARDED_FOR'; // $conf['page_cache_invoke_hooks'] = FALSE; if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { // uncomment if using domain access and testing on non-standard ports //$hosts = explode(':', $_SERVER['HTTP_HOST']); //if ($hosts) { // $_SERVER['HTTP_HOST'] = $hosts[0]; //} $conf['https'] = TRUE; $_SERVER['https'] = 'on'; $is_https = TRUE; $base_url = 'https://'.$_SERVER['SERVER_NAME']; } // uncomment if using domain access // include dirname(__FILE__)."/modules/domain/settings.inc";
Config côté Spip
Voir https://wiki.koumbit.net/SpIp#Configuration_en_arri.2BAOg-re_de_varnish
Wordpress
Wordpress is relatively easy to setup for caching. However, it should be noted that by default, wordpress does not send any header for setting max age, so a plain wordpress will not be cached! To make a wordpress site interact correctly with varnish, it is required that a caching plugin be installed in wordpress. Hypercache is a good plugin for this purpose.
The following VCL snippet will remove any cookie sent by client requests so that we can cache the same page for different ppl. If a cookie is set for authenticated users, it'll force requests to be sent to the backend:
# Drop any cookies sent to Wordpress. sub vcl_recv { if (!(req.url ~ "wp-(login|admin)")) { unset req.http.cookie; } } # Drop any cookies Wordpress tries to send back to the client. sub vcl_fetch { if (!(req.url ~ "wp-(login|admin)")) { unset beresp.http.set-cookie; } }
reference: https://www.varnish-cache.org/trac/wiki/VarnishAndWordpress
WP plugin: Proxy Cache Purge
Bon plugin pour gérer le purge des pages. Permet de tester le cache via: /wp-admin/admin.php?page=varnish-check-caching
Attention: certains plugins empêchent le caching!
Il y a certain plugin qui empêche le caching avec varnish, notamment par qu'ils utilisent des cookies spéciaux. On peut voir les plugins problématiques dans la page de test.
PolyLang: work around pour site multilangue
Si tu veux que WP puisse cacher un site qui utilise le plugin PolyLang, il faut suivre ce workaround:
https://dev.to/tammalee/busted-how-i-solved-a-varnish-cache-issue-238k https://polylang.pro/doc/is-polylang-compatible-with-the-eu-cookie-law/
Doc, il faut ajouter ceci à wp-config.php:
define( 'PLL_COOKIE', false);
On va encore avoir l'avertissement dans la page de test pour varnish, mais on voit que ça marche maintenant.
Putting in production: enabling DNS
Our setup is such that we have multiple varnish servers providing the CachingService. We therefore have one IP in the frontend that our LoadBalancingService redirects to the proper cache. That is the "virtual" cache.koumbit.net, which is not a real server, but just an entry in the load balancer.
"Normal" configuration
Normally, this would just be changing the A record of the main domain to point to the caching system while keeping the Apache vhost unchanged, so that it keeps on answering properly to varnish requests.
Basically, the domain still needs to be configured in Apache while the DNS needs to point somewhere else. The way to do this will vary according to the control panel and environment.
AlternC specific configuration
With AlternC, that's simply not possible because the DNS configuration is coupled with the Apache configuration. The workaround is to have a domain (say dynamic.example.com) that serves the dynamic website and is properly configured in AlternC, while the main domain (example.com) is an IP redirection to the caching system. Varnish also needs to be configured to access the server with the right hostname, using a directive like:
} elseif (req.http.host ~ "^(.*\.)?example.com$") { set req.http.host = "dynamic.example.com";
Since DNS and Apache configurations are coupled in AlternC, care needs to be taken when changing the configuration. It should be a process a bit like this:
add a dynamic.example.com pointer that points to the same place as example.com, test it
- 24h in advance, lower the TTLs to 5 minutes or skip to the next step
change the A pointer of example.com to the caching system directly in the zonefile (in /var/alternc/bind/zones/example.com)
- wait 5 minutes or 24h, depending if the TTL was changed
change the example.com domain to point to the IP in AlternC
Flusher la cache de Varnish
# varnishadm -T 127.0.0.1:6082 url.purge "."
Pour vider la cache:
- CLI accès root
- Il y a un varnish.module en développement pour Drupal, mais le problème est qu'il faut donner trop d'accès au varnish au site drupal et c'est pas sécuritaire.
- Module "purge" je ne pense pas, à cause des contrôles d'accès inexistants de varnish.
Aussi:
url.purge ^/$
... pour purger le frontpage. L'argument est simplement un URL, donc on peut purger n'importe quel objet de cette façon. Voir la documentation officielle pour plus d'information. Les modules expire ou purge permettent également d'intégrer ceci à Drupal.
Flusher le cache d'un seul site
On peut entrer dans le CLI de Varnish avec la commande (fonctionne avec Varnish 6.5) :
# varnishadm -T127.0.0.1:6082 -S /etc/varnish/secret
Varnish 3.x+ incluant 6.5
Pour tout flusher pour un certain site:
varnish> ban req.http.host == "www.example.com"
Pour flusher une page spécifique:
varnish> ban req.http.host == "www.example.com" && req.url ~ "^/pageblah$"
ref:
https://www.varnish-cache.org/docs/3.0/tutorial/purging.html
https://www.varnish-cache.org/docs/4.1/users-guide/purging.html
https://www.varnish-cache.org/docs/5.0/users-guide/purging.html
Varnish 2.x
varnish> purge req.http.host == www.example.qc.ca
Si tu veut flusher une page spécifique d'un site, il faut utiliser req.url et le syntax regex:
varnish> purge req.http.host == www.example.qc.ca && req.url ~ ^/pageblah$
Permettre à un client de flusher la cache
encore tiré de: https://www.varnish-cache.org/docs/3.0/tutorial/purging.html
@@ -4,6 +4,17 @@ # include "/etc/varnish/conf.d/"; # # but that's not supported by varnish yet +acl purge { + "localhost"; + "10.10.10.11"/24; + "199.58.80.233"; + "199.58.80.234"; + "199.58.80.237"; + backend default { .host = "127.0.0.1"; .port = "8080"; @@ -63,7 +74,30 @@ director microsites round-robin { { .backend = micro; } } +# from https://www.varnish-cache.org/docs/3.0/tutorial/purging.html +sub vcl_hit { + if (req.request == "PURGE") { + purge; + error 200 "Purged."; + } +} + +sub vcl_miss { + if (req.request == "PURGE") { + purge; + error 200 "Purged."; + } +} + sub vcl_recv { + # allow PURGE from localhost and 192.168.55... + if (req.request == "PURGE") { + if (!client.ip ~ purge) { + error 405 "Not allowed."; + } + return (lookup); + } + // Set this header so that backends can take evasive maneuvers in case of
Inspecting load balancer status
In load balancing setups (see below for examples), we can inspect the backend status using:
someserver# varnishadm -S /etc/varnish/secret -T127.0.0.1:6082 backend.list -p Backend sql01 is Healthy Current states good: 5 threshold: 3 window: 5 Average responsetime of good probes: 0.000559 Oldest Newest ================================================================ ---------------------------------------------4444444444444444444 Good IPv4 ---------------------------------------------XXXXXXXXXXXXXXXXXXX Good Xmit ---------------------------------------------RRRRRRRRRRRRRRRRRRR Good Recv ------------------------------------------HHHHHHHHHHHHHHHHHHHHHH Happy Backend web01 is Healthy Current states good: 4 threshold: 3 window: 5 Average responsetime of good probes: 0.038032 Oldest Newest ================================================================ ----------------------------------------------444444444444444444 Good IPv4 ----------------------------------------------XXXXXXXXXXXXXXXXXX Good Xmit ----------------------------------------------RRRRRRRRRRRRRRR-RR Good Recv -------------------------------------------HHHHHHHHHHHHHHHHHH-HH Happy Backend web02 is Sick Current states good: 0 threshold: 3 window: 5 Average responsetime of good probes: 0.000000 Oldest Newest ================================================================ ------------------------------------------HHH------------------- Happy Backend web03 is Sick Current states good: 0 threshold: 3 window: 5 Average responsetime of good probes: 0.000000 Oldest Newest ================================================================ ---------------------------------------------HHH---------------- Happy
If you need to interact with a varnish server that's older than 5.0, you might need to use the following command instead:
varnishadm -S /etc/varnish/secret -T127.0.0.1:6082 debug.health
Also note that on even older setups, you might need to drop the -S /etc/varnish/secret argument.
In the above examples, the 2 first nodes are "healthy" (ie. up and running) while the two last are "sick" (ie. down, non functionnal). In this example, the two last nodes were never configured, which explains why only one line is present.
For this to work, probes need to be configured, see documentation about health checks and documentation for probes for more information.
Watching the logs, stats
Varnish, since it's so high-performance and everything, doesn't log anything to logfiles by default, but instead writes logging information to a shared memory segment. There are a few utilities bundled with varnish to analyse that log.
varnishlog "tails" the log with very detailed instructions. See the varnishlog manpage for more detailed instructions and the wiki page for help in parsing the lines
varnishstats gives overview statistics, see the wikipage for explanations
- varnishhist gives a graph
Les cookies envoyés au client:
varnishtop -c -d -i TxHeader -I Set-Cookie:
Les URLs populaires:
varnishtop -d -i RxURL
Dumping the log to disk and reading it:
varnishlog -w tmp.log varnishlog -r tmp.log | less
Common configuration snippets
Custom error pages
this allows you to return custom HTML when an error occurs.
Load balancing
backend web01 { .host = "10.0.0.1"; .port = "80"; .probe = { .url = "/"; .interval = 5s; .timeout = 1 s; .window = 5; .threshold = 3; } } # ... director www round-robin { { .backend = web01; } { .backend = web02; } { .backend = web03; } }
This will probe the three backend nodes and load balance in a round-robin fashion between those. A weight can be put on each node to favor or disfavor them in the array. See this example for more information and this for probe configurations.
Changing the backend depending on the URL
The following configuration will set a different backend depending on the requested URL:
sub vcl_recv { if (req.url ~ "^http://(www.)?example.com/files/.*$") { set req.backend = static; } else { set req.backend = www; } }
Here we wanted to send all static files requests to the static, non-dynamic server to be even faster. We're changing the backend here, but in fact anything could be modified in the request here...
High-performance tweaks
A grace setting is important if we have a *lot* of concurrent connexions.
Otherwise the performance page is instructive and fun to follow.
Apache LogFormat to log the X-Forwarded-For
In file: /etc/apache2/apache2.conf
LogFormat "%v:%p %h %{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined LogFormat "%h %{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
The %{X-Forwarded-For}i will show the IP of the visitor that requested the page, since %h will show the IP of the Varnish server. You still want to keep %h, for example, if your SSL requests are hitting Apache directly.
Troubleshooting
503 errors
A website serving 503 errors intermittently is one of the most annoying things to troubleshoot with varnish.
The most common causes for this are:
backend is really slow; varnish backend timeout is reached
- verification of symptoms: run a loop that queries a page on the backend directly for 10 to 20 times and check the response times. if response times shoot higher than varnish's default backend request timeouts of 3.5s for connection or timeout for sending out the first byte after connection of 60s, then you need to make some adjustments to the backend.
solution: in the backend's definition block change the appropriate settings (you don't necessarily need to change both, start with bumping up the connection timeout only):
backend "patate" { // ... .connect_timeut = 10s; .first_byte_timeout = 90s; }
connection reuse might be causing bugs with apache mpm-itk
Varnish tends to reuse HTTP connections to pipe in more than one requests and save time on connection and handshake overhead. This behaviour, however, tends to cause bugs with apache mpm-itk
- the first request will make apache spawn a process with a certain UID and the first request is served correctly
a subsequent request hitting a different apache vhost will be reusing the same UID and will thus fail to access some files
So:
verification of symptoms: there are regularly permission errors in the apache error.log, eg.
[Fri Feb 14 16:59:36.445557 2020] [mpm_itk:warn] [pid 32595] (13)Permission denied: [client 199.58.80.104:60138] Couldn't read /var/alternc/html/a/xxx/www/xxx.ca/wp0/article1255.html, closing connection
- solution: disable connection keepalive for the affected backend apache (maybe just the affected vhosts):
<Virtualhost *:80> # ... KeepAlive off </VirtualHost>
c.f.: https://www.section.io/blog/varnish-cache-503-error-guru-meditation/
Testing and benchmarking
See VarnishTesting.
References
- varnish docs which may be relevant here:
VCL configuration documentation and examples -> dead links
How backends are pulled -> dead link