[Varnish](https://www.varnish-cache.org/) est un reverse-proxy HTTP. Il se met typiquement devant des serveurs HTTP et garde en cache les réponses autant que possible. Il gère également (un peu) le load-balancing entre les serveurs HTTP.
Le fichier `/etc/default/varnish` [n'est plus utilisé avec Systemd](https://bugs.debian.org/749272). Pour éviter toute confusion, on supprime ces fichiers :
Puis l'on personnalise la configuration via `/etc/systemd/system/varnish.service` (ne pas oublier de `systemctl daemon-reload` à chaque modification) :
*`-a` : spécifie *IP*:*port* sur lequel Varnish écoute pour les requêtes HTTP. On peut ainsi spécifier une IP secondaire pour coexister avec un autre service HTTP (Apache, Nginx) sur le port 80 (*-a 192.0.2.1:80*) ou faire écouter Varnish uniquement en local (*-a 127.0.0.1:8080*) ou alors le faire écouter de partout (*-a 0.0.0.0:80*) ou même spécifier plusieurs IP (*-a 0.0.0.0:80,127.0.0.1:81*)
*`-T` : spécifie l'interface d'admin de Varnish, accessible avec `varnishadm`
> *Note* : Pour Debian 8, le script `/usr/share/varnish/reload-vcl` utilise toujours `/etc/default/varnish`... on remplace donc `ExecReload=` par un script minimal :
>
> ~~~
> ExecReload=/etc/varnish/reload-vcl.sh
> ~~~
>
> avec `/etc/varnish/reload-vcl.sh` (à mettre en *chmod 700* bien sûr) :
Par défaut, Varnish n'écrit pas ses logs dans un fichier, mais dans un segment mémoire, ce qui permet d'augmenter grandement les performances. Quand l'espace est plein, Varnish réécrit par dessus en repartant de l'origine, ce qui fait que la mémoire allouée pour les logs n'augmente pas. On peut voir des logs en direct avec les outils varnishstat (stats de Varnish), varnishtop (*top* pour Varnish), varnishlog (logs verbeux) ou varnishnsca (logs au format NCSAcomme Apache) :
~~~
# varnishstat
# varnishtop -i ReqURL
# varnishlog
# varnishnsca
~~~
Des filtres peuvent être appliqués sur ces commandes, voici des exemples pratiques pour le debug :
Il est aussi possible d'écrire ces logs dans des fichiers en lançant varnishlog et varnishnsca en mode démon (lancés par défaut sous Debian 8). Ce démon est indépendant de *varnishd*, ce qui a l'avantage de ne pas ralentir les performances ; *varnishd* n'attend pas que la ligne de log soit écrite dans le fichier avant de servir la page : il l'inscrit en mémoire, et c'est ensuite *varnishlog* ou *varnishncsa* qui se chargera de copier la ligne dans le fichier sur le disque.
La syntaxe VCL est complexe mais puissante. On découpe un fichier VCL en plusieurs sous-routines dans lesquelles on définit des actions/comportements en fonction de certaines conditions. Les sous-routines principales sont *vcl_recv* et *vcl_backend_response* :
* **vcl_recv** est appelé AVANT le début de la requête au backend. On peut donc choisir vers quel backend renvoyer la requête. On peut aussi modifier la requête (modifier des entêtes HTTP, supprimer des demandes de cookies, etc.). Seules les actions `set req.` sont possibles.
* **vcl_backend_response** (remplace **vcl_fetch** depuis Varnish 4) est appelé APRÈS la réception de la réponse du backend. Les actions `set bereq.` (équivalentes à `set req.` dans *vcl_recv*) sont possibles, mais aussi `set beresp.` (pour *backend response*).
Attention, Varnish charge [ses propres sous-routines par défaut](#configuration-par-défaut) et si on veut changer son comportement il est impératif de copier la sous-routine par défaut (voir [#configuration-par-défaut]()) puis de la modifier !
S'il y a une erreur dans la configuration, Varnish échouera à redémarrer et cela risque d'impacter tous les sites qu'il cache. Il est donc indispensable de tester la configuration après toute modification.
Varnish compile la configuration en code C, il est donc possible de vérifier s'il y a des erreurs de compilation de la manière suivante :
Par défaut Varnish respecte le comportement standard d'un reverse-proxy : pas de cache en présence de cookie, respect des entêtes HTTP envoyés par le client et backend : sa configuration par défaut devrait convenir pour les sites codés correctement ! L'avantage (ou le piège) est que l'on peut facilement intervenir sur ce comportement standard pour ajouter des exceptions... si le code d'un site est incorrect.
Grâce aux règles VCL on peut vraiment définir finement la mise en cache ou pas, en complément des entêtes de cache renvoyés par le code. On peut ainsi mettre en cache même si certains cookies sont présents, en les supprimant de la requête.
Le temps de mise en cache (TTL) - si il y a mise en cache - est défini par la variable `beresp.ttl`.
Si le backend renvoie un entête HTTP `Cache-Control` contenant `max-age=` (ou `s-maxage=`) et/ou `Expires`, Varnish ajuste tout seul sa variable `beresp.ttl`.
On peut bien sûr définir `beresp.ttl`, mais attention cela va écraser la valeur déduite de Varnish, on conseille ainsi de faire :
~~~
sub vcl_backend_response {
# Default TTL if the backend does not send Expires or max-age/s-max-age headers
if (!beresp.expires && beresp.http.cache-control !~ "max-age=") {
set beresp.ttl = 1h;
#set beresp.http.Cache-Control = "max-age=3600";
}
}
~~~
À noter que l'on peut définir le TTL par défaut via l'option `-t` de [#varnishd]() mais on déconseille de le faire pour éviter toute confusion.
L'action `return (hash)` est le défaut de la sous-routine `vcl_recv` : cela fait passer le contenu dans la sous-routine `vcl_hash` qui stocke le contenu renvoyé afin de le resservir si applicable. Par défaut cela indexe le contenu grâce à l'URL et le `Host:` (pour gérer du multi-domaine):
~~~
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (lookup);
}
~~~
Cela n'est pas explicite mais si le serveur HTTP renvoie un entête `Vary:` (par exemple, `Vary: Accept-Encoding` ou `Vary: User-Agent`),
alors Varnish va automatiquement utiliser ce paramètre pour indexer le contenu, comme si l'on rajoutait un `hash_data()` sur les valeurs de `Vary:`.
Varnish ne permet pas de lister le contenu de son cache. En revanche, pour savoir si la taille du cache est correctement dimensionnée on peut se baser sur certaines valeurs retournées par la commande *varnishstat*, en particulier *MAIN.n_lru_nuked* qui est incrémentée à chaque fois qu'un objet est expulsé du cache pour pouvoir en cacher un autre :
~~~
# varnishstat -1 -f MAIN.n_lru_nuked
~~~
## Load-balancing
Si vous avez plusieurs serveurs web, Varnish gère le load-balancing : il permet de mettre plusieurs serveurs en backend et d'y accéder avec du round-robin. On peut également configurer une vérification de chaque backend, en précisant la page qui sert à la vérification et les paramètres (timeout, intervalle, etc.).
Voici un exemple avancé :
~~~
backend www00 {
.host = "192.0.2.6";
.port = "80";
.connect_timeout = 1s;
.first_byte_timeout = 3s;
.between_bytes_timeout = 2s;
.max_connections = 50;
.probe = {
.request = "GET / HTTP/1.1"
"Host: www.example.com"
"User-Agent: test Varnish"
"Connection: close"
"Accept-Encoding: text/html" ;
.timeout = 1000ms;
.interval = 5s;
.window = 8;
.threshold = 6;
}
}
backend www01 {
.host = "127.0.0.1";
.port = "80";
.probe = {
.url = "/"
.timeout = 800ms;
.interval = 10s;
.window = 8;
.threshold = 6;
}
}
director baz round-robin {
{ .backend = www00; }
{ .backend = www01; }
}
~~~
Une fois les backends ou directors définis, il faut les utiliser dans les règles. Par exemple :
* Gestion d'un poids pour chaque backend ? Oui, depuis Varnish 2.1.4 on peut préciser des poids pour chaque backend.
* Gestion du maximum de connexions pour un backend ? via le paramètre *.max_connections*
* Gestion d'un backend de secours ? via des règles VCL du type `if (!req.backend.healthy) { set req.backend = default; }`
* Gestion d'un mode sticky (par IP, URL ou user agent) ? cela se fait en remplaçant *round-robin* par client dans la définition du *director*. On peut ensuite définir quel est le paramètre à prendre en compte : `sub vcl_recv { set req.backend = baz; set client.identity = req.ip; /* ou client.url ou req.http.user-agent */ }`
Si besoin, on pourra aussi utiliser en complément le logiciel <http://trac.evolix.net/infogerance/wiki/HowtoHaproxy>
Varnish a une "killer feature" : le *grace mode*. En cas de backend HS, le contenu en cache continuera à être délivré pendant un certain temps même si il est sensé être expiré. Exemple de configuration :
Note : le *saint mode* (qui permet de laisser tranquille pendant un temps définir un backend qui aurait une erreur 500) n'existe plus avec Varnish 4.0... une nouvelle implémentation sera disponible en version 4.1 !
On peut se servir du retour de la commande *varnishadm* pour s'assurer du bon état de santé du démon. Ce plugin Nagios utilise ce principe : <http://exchange.nagios.org/directory/Plugins/Websites%2C-Forms-and-Transactions/check_varnish_health/details>.
La taille maximum d'un objet en cache ne semble limitée que par la taille du cache lui-même. Cela n'est malheureusement pas configurable comme avec Squid.
Il est communément admis que les cookies devraient rester sous la barre des 4096 octets (4 ko). Si vous avez beosin de faire transiter des cookies plus importants, il peut devenir nécessaire d'augmenter la valeur de `workspace_client`. la valeur par défaut est de `64k` et il ets préférable qu'elle reste un multiple de 4k. Attention que cette quantité de mémoire est allouée pour chaque requête, donc sur une instance à fort traffic ça peut grimper vite.
Pour augmenter la valeur, il faut ajuster la commande de démarrage de `varnishd` en ajoutant `-p workspace_client=96k` par exemple.
Quand un client HTTP interroge Varnish, il va le mettre en attente afin d'interroger le serveur HTTP final (si l'objet n'est pas caché). Pendant que le serveur HTTP final renvoie l'objet demandé à Varnish, le client HTTP est toujours mis en attente, le contenu lui sera renvoyé seulement une fois l'objet reçu à 100% par Varnish. Cela peut poser différents problèmes : dans le cas d'une grosse vidéo le démarrage sera lent, si le timeout du client HTTP est bas il peut fermer la connexion trop tôt, etc. Pour contourner ce problème, on peut utiliser le return *(pipe)* :