Varnish : Faites briller vos requêtes HTTP

Varnish

Dans le cadre de l’optimisation web, l’utilisation d’un reverse-proxy cache est devenu un incontournable. Dans cet article nous allons nous intéresser au plus connu d’entre eux: Varnish.

Son rôle est d’agir comme un passe-plat entre les clients de vos sites et votre serveur HTTP. Au passage il se permettra de garder en mémoire une copie des éléments statiques de vos pages pour les servir directement aux prochains visiteurs, pouvant réduire de plusieurs précieuses secondes vos temps de réponse. Les cas d’utilisation de Varnish sont innombrables, mais cet article se veut être une simple introduction, nous n’en aborderons donc qu’une petite partie.

Les mains dans le cambouis

Au lieu d’un long discours passons à la pratique avec quelques exemples. Pour cela, commençons par installer Varnish. Des dépôts sont mis à disposition pour les distributions Debian, Ubuntu, RedHat et FreeBSD sur le site officiel. Pour la suite de cet article nous utiliserons une Debian Wheezy.

On commence par ajouter le dépôt à la liste des sources APT, et par enregistrer la signature GPG qui lui est associée:

echo "deb http://repo.varnish-cache.org/debian/ wheezy varnish-3.0" >> /etc/apt/sources.list.d/varnish.list
curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add -

On peut maintenant mettre à jour le cache APT et lancer l’installation du paquet:

apt-get update
apt-get install varnish

Et voilà, le tour est joué !

Un premier tour de conf

Le fichier de configuration globale du daemon se trouve dans /etc/default/varnish et ressemble à ce qui suit:

START=yes

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

Avec l’option -a on indique l’adresse de bind et le port sur lequel Varnish attend les requêtes HTTP. Il est fixé par défaut à 6081 ce qui est parfait le temps de nos tests et quand le moment sera venu de passer en production c’est donc ici que nous pourrons par exemple décider de le faire écouter sur le port 80.

Les options -T et -S définissent respectivement l’interface/port de management et le fichier contenant le secret pour s’y authentifier. Via -s on définit le moyen de stockage du cache, la seule vraie option ici est d’utiliser le backend malloc qui va déléguer le stockage en RAM au système d’exploitation. Si vous n’avez pas assez de mémoire vive disponible envisagez d’en rajouter, mais surtout n’utilisez pas le stockage sur disque du cache comme solution car vous perdriez les bénéfices de Varnish.

Et enfin nous définissons avec l’option -f le chemin vers notre fichier de configuration VCL.

VCL, Késako?

VCL c’est le langage propre à Varnish permettant de configurer la gestion des requêtes et des objets présents dans le cache. On parle bien ici de langage car dans un soucis d’optimisation poussé à l’extrême, au chargement d’une nouvelle configuration, le daemon de management va traduire le VCL en code C et compiler ce dernier avant de l’attacher au daemon serveur.

C’est bien beau la théorie, mais à quoi ressemble-t-il notre fichier VCL? Ouvrons le fichier /etc/varnish/default.vcl pour le découvrir dans sa plus simple expression:

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

Un backend est un serveur auquel Varnish va passer les requêtes qu’il reçoit. Il est défini par un couple IP/port. En l’état, toutes les requêtes entrantes seront redirigées vers le backend par défaut, vers le port 8080 en local.

Caching par défaut

Varnish ne place jamais en cache les requêtes qui contiennent des paramètres de type POST ou accompagnées de cookies, que ces derniers soient envoyés par le client ou renvoyés par le backend. Il est donc à noter que si votre site en utilise, par exemple pour tracker le comportement de vos utilisateurs via Google Analytics, aucun contenu ne sera mis en cache. Pour palier à cela nous pouvons nettoyer nos appels de ces méchants biscuits:

sub vcl_recv {
    unset req.http.cookie;
}

sub vcl_fetch {
    unset beresp.http.set-cookie;
}

Au passage nous découvrons deux des sous-routines proposées par Varnish. Chacune d’elle représente une des étapes de traitement des requêtes.

Varnish VCL
Varnish VCL
  • vcl_recv est la première à être exécutée lors de la réception d’une requête, elle intervient donc en amont des opérations de recherche dans le cache.
  • vcl_fecth est quant à elle la première appelée à la réception de la réponse du backend, avant les opérations de mise ne cache. Via la fonction unset, on déréférence les objets contenant les cookies, contournant ainsi le comportement par défaut et permettant à nos requêtes d’utiliser le cache.

De l’avis même des développeurs de Varnish, dans 99% des cas tous les changements de configuration dont vous aurez besoin se feront dans ces deux sous-routines.

Dans l’exemple ci-dessus, la méthode est un peu brutale car tous les cookies sont effacés sans distinction, ce qui est bloquant pour un site faisant usage des sessions…

On peut affiner notre action en nettoyant uniquement les requêtes vers nos images, ce qui semble déjà plus pertinent:

sub vcl_recv {
 if (req.url ~ "\\.(png|gif|jpg)$") {
    unset req.http.cookie;
 }
}

sub vcl_fetch {
 if (req.url ~ "\\.(png|gif|jpg)$") {
   unset beresp.http.set-cookie;
 }
}

On peut noter le support des expressions régulières qui donnent une grande flexibilité à outil. Il est ainsi possible d’appliquer cette règle pour tous les fichiers d’un dossier au lieu de se baser sur leurs extensions, ou encore de manipuler l’objet req.http.cookie à l’aide des regex pour ne laisser passer que certains cookies.

Une porte d’entrée vers vos différents backends

Actuellement, les serveurs applicatifs spécifiques à des langages pullulent et génèrent des environnements très hétérogènes entre les projets. On peut citer entre autres Node.JS (Javascript), Thin (Ruby) ou encore Gunicorn (Python). Dans ce cas Varnish permet de créer un point d’entrée unique et très performant pour répartir les requêtes vers les bons backends tout en réduisant largement les appels qui leurs seront faits et donc leur consommation de ressources système.

Imaginons que nous voulions héberger un site statique via Nginx à l’adresse static.example.com, et un blog Ghost sur NodeJS à l’adresse ghost.example.com.

Exemple Varnish
Exemple Varnish

Pour cela il faut commencer par déclarer les deux backends:

backend nginx {
    .host = "127.0.0.1";
    .port = "80";
}

backend nodejs {
    .host = "127.0.0.1";
    .port = "2368";
}

Il suffit ensuite de modifier l’objet req.backend dans la sous-routine vcl_recv pour sélectionner le backend vers lequel envoyer la requête en fonction de l’hôte http appelé:

sub vcl_recv {
    if (req.http.host ~ "^static.example.com$") {
        set req.backend = nginx;
    }
    
    if (req.http.host ~ "^ghost.example.com$") {
        set req.backend = ghost;
    }
}

Répartissez votre charge

Varnish est capable de gérer la répartition de charge via des backends spécifiques appelés directors. Parmi les plus utilisés on trouve le round-robin director qui distribue les requêtes de manière alternative aux backends et le client director qui route les requêtes en fonction d’un cookie de session, permettant qu’un même client soit toujours renvoyé vers le même backend.

La mise en oeuvre des directors est très simple. On commence par définir plusieurs backends:

backend nginx_1 {
    .host = "192.168.0.1";
    .port = "80";
}

backend nginx_2 {
    .host = "192.168.0.2";
    .port = "80";
}

Ensuite un director pour les associer:

director nginx_director round-robin {
    { .backend = nginx_1; }
    { .backend = nginx_2; } 
}

Et enfin on définit ce director comme backend pour nos requêtes:

sub vcl_recv {
    set req.backend = nginx_director;
}

Pour aller plus loin

Si vous désirez étendre les fonctionnalités de Varnish, il existe des plugins, appelés VMOD, disponibles sur le site officiel. Plusieurs utilitaires sont aussi disponibles, dont un dashboard ou encore un plugin Nagios que vous trouverez sur cette page dédiée.

Bonne optimisation ;)

Vus : 1800
Publié par Wooster by CheckmyWebsite : 49