Booster votre blog WordPress avec Varnish

Publié le 12 octobre 2010 par Nicolargo

Varnish est un accélérateur de sites Web fonctionnant sur le principe d'un reverse proxy. Varnish va prendre en charge les requêtes HTTP venant de vos visiteurs et communiquer avec votre serveur Web en ne demandant la création des pages Web seulement quand cela est nécessaire.

C'est un projet open-source sous licence FreeBSD.

Installation

Sur un Ubuntu Server (ou une distribution Debian "like"), l'installation se résume à la commande suivante:

sudo aptitude install varnish

Nous allons donc dans un premier temps tester Varnish sur la configuration initiale de notre serveur Web (qui comprend dans mon exemple deux sites virtuels sous Apache). Cette configuration de test permettra de tester les performances de Varnish sans aucun impact sur vos sites (les visiteurs continueront à passer directement par votre serveur Web Apache). Enfin, si les tests sont concluants, nous modifierons la configuration finale pour que vos visiteurs transitent de manière transparente par Varnish.

Configuration de test

Varnish appelle backend les serveurs Web qu'il doit accélérer. Il est possible de définir un ou plusieurs backends par serveur Varnish.

Ainsi, si l'on souhaite accélérer les sites http://www.nicolargo.com et http://blog.nicolargo.com qui sont hébérgés sur la même machine, il faut saisir la configuration suivante dans le fichier /etc/varnish/default.vcl (configuration librement inspiré de la documentation officielle sur comment optimiser son blog WordPress avec Varnish):

backend www {

.host = "www.nicolargo.com";

.port = "80";

}

backend blog {

.host = "blog.nicolargo.com";

.port = "80";

}

Dans le même fichier on doit définir la fonction vcl_recv afin de l'adapter à notre configuration WordPress (gestion du cache sur les requête POST, pas de cache pour la zone admin, gestion des cookies de Google Analytics...):

sub vcl_recv {

if (req.http.host ~ "(www\.nicolargo\.com|nicolargo\.com)") {

set req.backend = www;

} elsif  (req.http.host ~ "(blog\.nicolargo\.com)") {

set req.backend = blog;

}

# Compatiblity with Apache log

remove req.http.X-Forwarded-For;

set    req.http.X-Forwarded-For = client.ip;

# Normalize Content-Encoding

if (req.http.Accept-Encoding) {

if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|lzma|tbz)(\?.*|)$") {

remove 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 {

remove req.http.Accept-Encoding;

}

}

# Gestion des cookies de Google Analytics

if (req.http.cookie) {

set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", "");

if (req.http.cookie ~ "^ *$") {

remove req.http.cookie;

}

}

# Remove cookies and query string for real static files

if (req.url ~ "^/[^?]+\.(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)(\?.*|)$") {

unset req.http.cookie;

set req.url = regsub(req.url, "\?.*$", "");

}

# Pas de cache pour les requêtes POST

if (req.request == "POST") {

return(pass);

}

# Pas de cache pour l'interface d'administration de WordPress

if( req.url ~ "^/wp-(login|admin)" || req.http.Cookie ~ "wordpress_logged_in_" ){

return(pass);

}

}

Le port d'écoute par défaut de Varnish est  TCP/6081 (défini dans le fichier /etc/default/varnish).

Si vous avez un Firewall (iptables) sur votre serveur, il faut penser à ajouter la règle suivante:

iptables -A OUTPUT -p tcp --dport 6081 -j ACCEPT

On relance Varnish pour prendre en compte la configuration:

sudo /etc/init.d/varnish restart

Si tout marche bien, vos sites doivent s'afficher avec les URL: http://www.nicolargo.com:6081 et http://blog.nicolargo.com:6081 (à remplacer par vos sites hein, faite pas les boulets...).

Tests sur le site statique

Test local sur le site statique (avec uniquement des éléments statiques page HTML & images).

Test sur une page statique (HTML simple) sans Varnish:

ab -t 30 -c 5 http://www.nicolargo.com/

Requests per second:    651 [#/sec] (mean)

Time per request:       7.6 [ms] (mean)

Test sur une page statique (HTML simple) avec Varnish:

ab -t 30 -c 5 http://www.nicolargo.com:6081/

Requests per second:    652 [#/sec] (mean)

Time per request:       7.6 [ms] (mean)

Sur notre site Web statique, on n'a donc pas de gain au niveau de la capacité maximale de montée en charge du serveur Apache (Requests per second). Ce qui est normal vu qu'Apache n'a pas grand chose à faire pour servir ce genre de page. Par contre on observe une occupation mémoire moindre pendant le test avec Varnish (environ 10% de moins).

Tests sur le site dynamique (WordPress)

Test en local sur le site Web dynamique (WordPress, déjà optimisé en suivant ce tutoriel).

Test sur la page index d'un blog WordPress sans Varnish:

ab -t 30 -c 5 http://blog.nicolargo.com/

Requests per second:    588 [#/sec] (mean)

Time per request:       8.5 [ms] (mean)

Test sur la page index d'un blog WordPress avec Varnish:

ab -t 30 -c 5 http://blog.nicolargo.com:6081/

Requests per second:    3460 [#/sec] (mean)

Time per request:       1.5 [ms] (mean)

Sur notre site dynamique, la valeur ajoutée de Varnish est importante car on a ici un gain de plus de 488% en terme de nombre de requêtes simultanées que votre serveur peut fournir. Sur une page dynamique un peu plus lourde (par exemple un billet avec beaucoup de commentaires), le gain peut alors monter jusqu'à 650%.

Attention, cela ne veut pas dire que votre blog va s'afficher 488% plus vite avec Varnish mais "seulement" que votre serveur pourra accepter 488% de requêtes simultanées maximales en plus.

Configuration finale

Une fois votre site accéléré validé, il faut passer Varnish en production. Les actions suivantes sont à effectuer.

Configurer le serveur Apache hébergeant votre blog pour écouter sur un port différent du port TCP/80 (par exemple TCP/8080). Sous Ubuntu Server, on commence par modifier le fichier /etc/apache2/ports.conf pour lui demander d'écouter les requêtes HTTP sur le port 8080 en lieu et place du port 80:

NameVirtualHost *:8080

Listen 8080

On modifie ensuite le fichier de configuration de nos sites /etc/apache2/site-enabled/virtualhosts: (notez bien la modification du port :8080 et l'utilisation du format de log varnishcombined)

# WWW

<VirtualHost *:8080>

DocumentRoot /var/www/www

ServerName nicolargo.com

ServerAlias www.nicolargo.com

ServerAdmin contact@pasdespam.com

CustomLog /var/log/apache2/www-access.log varnishcombined

ErrorLog /var/log/apache2/www-error.log

</VirtualHost>

# BLOG

<VirtualHost *:8080>

DocumentRoot /var/www/blog

ServerName blog.nicolargo.com

ServerAdmin contact@pasdespam.com

CustomLog /var/log/apache2/blog-access.log varnishcombined

ErrorLog /var/log/apache2/blog-error.log

</VirtualHost>

On configurer le serveur Apache pour loguer les adresses sources et non pas l'adresse du serveur Varnish. Il suffit pour cela d'ajouter la ligne suivante dans le fichier /etc/apache2/apache2.conf:

LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnishcombined

La configuration d'Apache est maintenant fini, il faut alors configurer Varnish pour écouter sur le port TCP/80 et changer la configuration du "backend" en éditant la section suivante du fichier /etc/default/varnish:

DAEMON_OPTS="-a :80 \

-T localhost:6082 \

-f /etc/varnish/default.vcl \

-S /etc/varnish/secret \

-s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"

La dernière chose à faire si votre serveur est protégé par un Firewall IpTables est de modifier la règle ajoutée dans le premier chapitre de ce billet et d'y ajouter une nouvelle règle pour une éventuelle administration locale de Varnish à l'aide de l'utilitaire varnishadm:

iptables -A OUTPUT -p tcp --dport 8080 -j ACCEPT

iptables -A OUTPUT -p tcp --dport 6082 -s 127.0.0.1 -j ACCEPT

On prend en compte la configuration finale en relancant les deux processus (Apache et Varnish):

sudo /etc/init.d/apache2 restart

sudo /etc/init.d/varnish restart

A partir de ce moment là, toutes les requêtes HTTP de vos visiteurs seront d'abord prise en compte par Varnish (sur le port TCP/80) puis ensuite, si nécessaire, par votre serveur Apache (TCP/8080).

Quelques commandes utiles

  • varnishlog: Affichage du log du daemon Varnish.
  • varnishstat: Affichage des statistiques d'utilisation de Varnish.
  • varnishhist: Affiche un historique sous forme de graphe des requêtes faites à votre serveur Varnish.
  • varnishadm: une interface d'administration locale de Varnish

Vous pouvez également consulter la documentation en ligne à l'adresse suivante.

Encore un problème... please help...

Après une demi journée de tests sur mon blog, la configuration s’avère presque concluante. "Presque" parce que j'ai encore un problème de gestion des cookies de WordPress. En effet, ils ne semblent pas être gardé en mémoire au niveau de mon navigateur Web. Ainsi si je rentre un commentaire WordPress sur mon blog (avec les informations nom, adresse mail et URL), ces dernières sont oubliées dés que le commentaires est posté. Je ne suis pas un spécialiste de la syntaxe (complexe) des fichiers de conf VCL mais c'est surement là qu'une modification est à faire. J'ai fait quelques tests non concluants. Si vous avez une configuration aux petits oignons Varnish + WordPress, je suis preneur !