Configuration Varnish+Nginx pour WordPress

Date: 11/09/2011 | Catégories: Blog,Open-source,Planet-libre,Web | Tags: ,,,,,,

Vu le nombre d'articles sur l'utilisation du serveur de cache Varnish pour une utilisation avec le CMS WordPress, force est de constater qu'il est difficile de faire le tri pour en sortir LA configuration. Dans ce billet, je vais donc vous présenter ma configuration qui tourne depuis quelques jours sur le serveur hébergeant le Blog de Nicolargo.

Ce serveur sous Debian Squeeze est composé de:

  • Varnish
  • Nginx avec le module PHP-FPM
  • WordPress avec le plugin "Varnish HTTP Purge"

Je maintiendrai à jour une configuration stable (avec des commentaire en Anglais) de cette pile HTTP dans le GIT suivant:

https://github.com/nicolargo/varnish-nginx-wordpress

Une configuration pour quoi faire ?

Le principal objectif est d'optimiser votre serveur pour supporter une montée en charge pouvant aller jusqu'à plusieurs centaines de requêtes HTTP par seconde. C'est à dire une configuration adaptée pour une grande majorité des blogs personnels à fort trafic.

Avec une pile HTTP classique (c'est à dire sans cache), toutes les requêtes vers WordPress vont entraîner:

  • l'exécution d'un script PHP générant en sortie un fichier HTML
  • des requêtes vers la base de donnée MySQL
  • la lecture sur disque des éléments statiques de la page (fichiers CSS, JS, images...)

Lors de ces premières requêtes il est important d'avoir un thème bien optimisé. Le plugin W3 Total Cache peut vous aider dans cette démarche en optimisant les fichiers CSS (compression / regroupement) et en mettant dans un cache certaine requêtes SQL. Il faut également noter qu'avec un système de cache externe comme Varnish, la première requête va également engendrer ces actions mais pas les suivantes.

Les deux premiers points sont fortement consommateurs de ressources matérielles (CPU et mémoire). Ainsi, la charge globale de votre serveur augmente avec le nombre de requêtes simultanées. Arrivé à saturation, votre serveur ne peut plus répondre correctement aux requêtes et le temps de chargement de vos pages commencent à augmenter jusqu'à arriver au point ou il n'est plus capable de rien faire.

L'utilisation d'un cache comme Varnish permet de fournir directement les fichier HTML au navigateur client sans passer par l’exécution du script PHP et les requêtes MySQL.

Concernant le troisième point, le problème vient de la relative lenteur des accès disques (notamment si vous êtes sur un hébergement de type virtuel (aka) VPS).

Une optimisation possible est de lire les objets statiques non pas depuis le disque mais directement depuis un cache mis en RAM. Deux solutions sont possibles, soit faire effectuer cette tache par Varnish (que l'on peut optimiser en utilisant un disque tmpfs pour le répertoire de travail de Varnish) qui en plus des pages HTML va également "cacher" les objets statiques, soit laisser NGinx gérer cela directement, notamment en utilisant une brique comme Memcached. Si les deux sont comparables en terme de performances pures (c'est à dire la capacité à supporter un grand nombre de requêtes simultanées), il semble que NGinx est une consommation CPU moins importante.

Avant de cacher il faut savoir purger

Les lecteurs attentifs ont déjà dû noter qu'il y avait un trou dans la raquette dans l'exposé précédant. En effet, par définition, WordPress génère des sites dynamiques ou les articles peuvent évoluer, des commentaires peuvent être ajoutés. Il faut donc un mécanisme pour prévenir Varnish de mettre à jour son cache quand certaines actions sont faites sur le blog.

Heureusement pour nous, WordPress dispose d'un grand nombre de plugins permettant d'automatiser cette tache. W3 Total Cache, déjà mentionné dans le premier chapitre dispose d'une option pour  communiquer avec Varnish. Il semble cependant qu'il y est des problèmes quand l'on configure ce plugin avec plusieurs serveurs Varnish (pour faire du partage de charge). Je conseille donc l'utilisation d'un plugin ne faisant que la tache de purge:  Varnish HTTP Purge.

Il faut donc désactiver la fonction de purge Varnish dans W3 Total Cache (si ce dernier est installé):

puis activer le plugin Varnish HTTP Purge:

On passe aux résultats

Pour avoir un "test bed" stable, j'ai installé les briques sur une machine dédiée sous Debian Squeeze. J'ai ensuite rédigé un billet de test comprenant du texte et 3 images.

Test de montée en charge locale avec Apache Bench

Dans un premier temps j'ai utilisé l'utilitaire Apache Bench (utilitaire ab) qui permet de simuler en local (c'est à dire sans les contraintes réseau) un grand nombre de requêtes simultanées sur l'URL du billet de test.

Sans Varnish / Sans W3 Total Cache:

[cce lang="bash"]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

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

[/cce]

=> CPU proche de 95% pendant le test.

Sans Varnish / Avec W3 Total Cache:

[cce lang="bash"]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

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

[/cce]

=> CPU proche de 85% pendant le test.

On note une augmentation des performances mais la charge CPU reste forte. Les processus PHP-FPM sont nombreux.

Avec Varnish / Sans W3 Total Cache:

[cce lang="bash"]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

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

[/cce]

=> CPU proche de 30% pendant le test.

Le gain est impressionnant par rapport à la configuration sans Varnish. On atteint un nombre de requêtes par seconde très important (> 8000 en moyenne) avec une marge CPU ne dépassant pas les 35% !

Avec Varnish / Avec W3 Total Cache:

[cce lang="bash"]

# ab -c 5 -t 30 http://blogtest.nicolargo.com/2011/09/lorem.html

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

[/cce]

=> CPU proche de 30% pendant le test.

Comme on n'a pas ou peu de gain supplémentaire en utilisant W3 Total Cache en plus de Varnish. J'ai donc décidé de ne plus utilisé W3 Total Cache sur mon blog WordPress. Il sera remplacé par "Varnish HTTP Purge" pour la gestion des purges de Varnish et "WP Minify" pour la réduction automatique des fichier CSS et JavaScript.

Test de montée en charge online avec Blitz.io

Si vous ne connaissez pas le service Blitz.io, je vous conseille la lecture du très bon billet de Romain sur le sujet.

J'ai utilisé la commande "rush" suivante:

[cce]

--timeout 5000 --region ireland --pattern 1-250:60 http://blogtest.nicolargo.com/2011/09/lorem.html

[/cce]

NGinx seul:

A partir de 50 utilisateurs, le temps de chargement des pages commence à augmenter pour arriver au timeout (limité à 5 secondes pour les tests chez Blitz.io) vers 120 utilisateurs.

NGinx avec Varnish:

Dans cette configuration, je ne rencontre aucune chute de performance avec 250 utilisateurs simultanés.

Grâce à Romain (encore lui) j'ai pu lancer sur le Blog de Nicolargo (Varnish + Nginx) un test avec 500 utilisateurs simultanés (par défaut Blitz.io est limité à 250).

Voici le résultat sur le Blog de Nicolargo:

Pas de problème jusqu'à 500 utilisateurs simultanés !!!

Test des purges

Pour valider que le plugin "Varnish HTTP Purge" fonctionnaite bien j'ai effectué les taches suivantes en vérifiant que la page était bien mise à jour pour un lecteur lambda:

  • Modification d'un billet existant
  • Suppression d'un billet existant
  • Ajout d'un commentaire
  • Modification d'un commentaire
  • Suppression d'un commentaire

Tous les tests ont été concluant.

Conclusion

Le couple Varnish + Nginx est donc une des pile que l'on peut utiliser pour obtenir un blog performant et résistant à une montée en charge bien supérieure aux nombres maximum de visiteurs sur la plupart des sites Internet. Ce n'est bien pas la seule solution et il existe sûrement des piles encore plus optimisé (notamment au niveau statique avec un serveur comme G-WAN), mais il est de mon point de vu, celui qui offre le meilleur ratio stabilité/sécurité/performance.

Pour suivre l'activité de la configuration étudiée dans ce billet, je vous conseille de vous abonnez au projet GitHub.

Quelques unes des sources de ce billet:

  • http://www.it-wars.com Vincent RABAH

    Bravo, je vais faire la même chose sur mon blog :)

  • https://blog.tengu.ch/ SwissTengu

    Hello!

    Je viens de voir que tu parles de g-wan – l’as-tu testé? Si non, je t’invite à lire ce thread (parmis d’autres) http://swisslinux.org/forum/viewtopic.php?id=2750

    Si oui: est-ce que les perfs sont réellement à la hauteur de ce que l’auteur annonce ? Est-ce qu’une config adaptée pour nginx ne rendrait pas ce dernier aussi rapide (voire plus) ?

    Bref, si tu as un retour sur la chose, c’est bien volontier. Vu comment est l’auteur, et ce qu’il sort comme histoires à propos du code fermé (et de ses raisons), ça m’a un peu refroidi…

    ++
    T.

    • http://www.nicolargo.com NicoLargo

      Non, je n’ai pas testé G-WAN et je le ferais pas tant que l’auteur ne fournira pas ses sources…

      • https://blog.tengu.ch/ SwissTengu

        Ah tien… toi aussi? ;)
        Bref. Config intéressante, mais je suis presque sûr que varnish n’est pas utile dans ce genre de config, du moins tant que tu n’as qu’un seul serveur. Il serait intéressant de faire des tests avec une config nginx correct, et emploi de memcached en lieu et place du storage “file” de base de nginx pour la mise en cache.

  • Pingback: Configuration Varnish+Nginx pour WordPress | LorfDotNet()

  • Pingback: Configuration Varnish+Nginx pour Wordpress | Wordpress | Scoop.it()

  • http://www.djoh.net/inde/ Djoh

    Je pense que la réponse est négative, mais utilises-tu / penses-tu essayer CloudFlare en plus de cette pile ?

  • http://www.woueb.net Romain

    Bien !
    Je vais tester aussi Nginx bientôt je pense.
    Ce qui est bien, c’est que je peux le faire en parallèle sur un autre port qu’Apache, et juste rediriger Varnish au bon moment… ^^

    J’ai un peu de mal avec W3 Total Cache et la purge de Varnish, je vais essayer l’autre extension dont tu parle ! :)

  • JaCe

    Pourquoi demander a varnish de faire ce que sait faire servertoken et expose_php ?

    • http://www.nicolargo.com NicoLargo

      Je ne vois vraiment pas le rapport…

      • JaCe

        La question n’est pas assez claire?

        • http://www.nicolargo.com NicoLargo

          Ben non…

          • JaCe

            C’est triste alors :-/

        • http://www.woueb.net Romain

          J’avoue également ne pas comprendre ta question : c’est peut-être clair dans ta tête mais je vois pas…

  • Pingback: Nicolargo : Configuration Varnish+Nginx pour WordPress | Actualités de l'open source | Scoop.it()

  • http://twitter.com/webwolf_hosting Melanie Shepherd

    is there any possibility that you could help me install this? :)

  • Steve

    Bonjour Nicolas,

    Merci pour cet excellent billet.

    Est-ce que tu saurais me dire si, avec cette configuration, le htaccess est bien géré?

    Pour un projet que j’ai en tête, offrir de l’hébergement pour WordPress, cette configuration me semble bien. Je suis en test présentement avec apache/nginx et APC, le tout avec W3 Total Cache. Mais si je peux enlever la couche qu’est W3 Totla Cache, cela m’enlèverait sûrement des requêtes au niveau du support technique..

  • Steve

    Vous avez un petit moment au sujet de mon dernier commentaire?

  • http://elliptips.info Robin

    Bonjour Nico,

    Tout d’abord, je souhaite te remercier pour l’excellente section hébergement que tu tiens à jour sur ce blog. Ayant plus un profil de développeur à la base, si je m’intéresse à ce domaine depuis quelque temps, c’est en grande partie grâce à ton site :)

    Si je poste ici, c’est parce que cela fait plusieurs soirs que je galère avec la configuration de Varnish. C’est une première pour moi (de même pour Nginx) et je dois avouer que je suis un peu perdu. Je me suis aidé de ton article (http://blog.nicolargo.com/2011/08/installation-pas-a-pas-dun-serveur-de-blog-wordpress-sur-debian-squeeze.html) pour l’installation et j’ai récupéré les dernières conf sur ton Github.

    Varnish est donc en place et j’arrive à me rendre sur mon blog. Par contre, lorsque j’édite, ajoute ou supprime un billet, le cache Varnish ne semble pas se purger. J’ai d’abord cru à un problème avec Varnish HTTP Purge et lorsque que je tente une purge manuelle via curl (curl -X PURGE http://home_de_mon_blog), j’obtient bien le code 200 Purged, mais rien à faire, en retournant sur la home, l’article n’est pas mis à jour. Lorsque je relance Varnish, le cache est bien vidé et la home mise à jour.

    Bref, étant donné que Varnish répond correctement à une purge manuelle, je ne comprends pas pourquoi j’obtiens la version encore en cache…

    Merci d’avance si tu as un peu de temps pour me répondre :)

    • http://www.nicolargo.com nicolargo

      Bizzare, le seul truc que je peux imaginer est un problème de configuration de Varnish qui ne prend pas en compte le purge venant du plugin WordPress.

      Peux tu nous partager par pastebin le fichier de conf de Varnish default.vcl que tu utilises ?

      • http://elliptips.info Robin

        Merci pour ta réponse.

        Voici ma configuration pour le fichier default.vcl :

        http://pastebin.com/ftECX6ku

        J’ai seulement modifié l’adresse du blog (qui pour l’instant est sur un sous domaine pour mes tests et l’adresse IP de mon serveur)

        • http://www.nicolargo.com nicolargo

          La conf me semble bonne (d’un autre coté c’est la mienne :)). Regarde du coté des logs (système pour un éventuel bloquage via Firewall) et web (log NGinx et Varnish).

          Le mieux est de générer un purge en créant un nouveau billet ou en effaçant un existant) puis de nous binposter les logs.

      • Robin
  • Robin

    D’après ce que j’ai compris, Varnish ne log rien sur le disque. J’ai donc activé les logs dans le fichier varnishlog mais le résultat semble illisible. Bref, voici mes fichiers :

    /var/log/messages :

    http://sebsauvage.net/paste/?efc1e88d4414b445#O+t+puXNyaRVvZcFywdVgWoJbD3CTTknBDy8eNY710E=

    /var/log/varnish/varnish.log :

    http://sebsauvage.net/paste/?a164d734b4c26a42#P9adWny3dy0W/P9XgBVa+ufYZvLcZ8/x9csgD8Cydac=

    /var/log/nginx/blog.access_log

    http://sebsauvage.net/paste/?fe57d3e65aed6966#PtjRqO8OZksHq+kUEZDo8Jlj4rhVL+TJNVY4bmSfPeY=

    Pour le firewall, j’avais essayé en supprimant toute mes rêgles (j’utilise aussi ton script :p)