Varnish & les Edge Side Includes pour faire du cache partiel de page

ESI – ou Edge Side Includes – est une solution de mise en cache partiel de page. L’idée générale est d’avoir des « portions » de la page qui sont servis avec différentes règles de mise en cache que le reste de la page.

On peut imaginer une page qui sera mise en cache dans sa globalité, sauf le petit widget « panier » qui lui ne sera pas mis en cache. Une problématique extrêmement fréquente et qui empêche généralement toute mise en cache, alors qu’on n’a qu’un tout petit morceau de la page qui est réellement dynamique :(
L’idéal serait alors que la page soit mise en cache complètement, et que sa partie dynamique soit simplement identifiée par un « marqueur », et que la navigateur aille chercher le contenu de ce « marqueur » à une autre adresse, qui elle a une politique de mise en cache différente.

Et bien c’est ce que propose ESI :) Le marqueur en question est un tag XML <esi src="adresse du morceau de page à rendre" />. Par contre les navigateurs ne comprennent pas ce langage directement, il faut donc ajouter entre les deux un « proxy cache » qui lui saura interpréter ces portions, et rendre au navigateur le résultat final.

L’intérêt immédiat est de soulager le serveur, et de desservir bien plus rapidement la page : si dans la page le seul élément à calculer est ce panier, pourquoi s’embêter à demander le reste au serveur HTTP ? C’est le proxy cache qui se charge de faire l’intermédiaire :

Ainsi la plupart du temps, le serveur HTTP ne génèrera effectivement que la partie « panier.php ». On soulage vraiment le serveur, on ne change rien pour le client (enfin si, on lui répond plus vite ;)), et le proxy fait son taf habituel en desservant des fichiers qu’il a en cache. Il n’est donc pas très fatigué non plus.

Mise en œuvre

D’abord il faut un serveur web, et un proxy cache sur votre machine. Dans mon cas j’ai installé nginx et varnish :

sudo apt-get install nginx varnish

Le serveur HTTP

D’abord, un petit server nginx :

1
2
3
4
5
6
7
8
server {
        listen   8000;
        server_name  test-esi.localhost;
        gzip off; # Très important ! Varnish ESIFeatures ne marchera pas avec le gzip actif
        location / {
                root   /home/naholyr/Sites/TestESI;
        }
}

Avec ça j’ai un serveur écoutant le port 8000 pour l’hôte « test-esi.localhost« .

Je vais créer deux fichiers :

1. Mon index.html

1
2
3
4
5
6
<html>
<head><title>Test ESI</title></head>
<body>
<esi:include src="partial.html">
</body>
</html>

2. Mon partial, référencé dans l’index

1
coucou gamin

Voici ce qu’on obtient en allant sur http://test-esi.localhost:8000

Rien, c’est normal, le tag « <esi:include /> » n’est pas interprété par le navigateur ! Ne vous moquez pas, la première fois que j’ai entendu parler des Edge Side Includes, j’ai cru que c’était un tag HTML magique pour remplacer les iframes et je cherchais où était le piège. Pas de piège, ce n’est pas un information du HTML, c’est une information destinée à un autre protocole, puisqu’il est destiné à l’acteur « en bout de chaîne » (d’où le « edge side »), c’est à dire le proxy :)

C’est là que Varnish entre en jeu.

Activation et configuration de Varnish

Si vous venez d’installer Varnish, et que vous êtes comme moi sous Ubuntu, il est inactif par défaut. Quand on démarre le service il répond laconiquement « Not starting HTTP Accelerator… ». Éditez le fichier /etc/default/varnish, et remplacez « START=no » par « START=yes« , puis redémarrez le service avec « sudo service varnish restart« .

Par défaut, Varnish tourne sur le port 6081. Ça ira bien pour nos tests, mais si vous voulez le faire tourner sur un autre port éditez le fichier précédent et modifiez l’option « DAEMON_OPTS« .

Ensuite, créons le proxy qui va bien en éditant le fichier /etc/varnish/default.vcl :

1
2
3
4
5
6
7
8
9
10
backend testesi {
        .host = "test-esi.localhost";
        .port = "8000";
}
sub vcl_recv {
        if (req.http.host ~ "^test-esi.localhost(:\d+)?$") {
                set req.backend = testesi;
        }
        # ...
}

On redémarre Varnish, et on accède à http://test-esi.localhost:6081. Si tout va bien, on a ça :

w00t ! Epic win 😀

Si jamais ça ne marche pas chez vous, reprenez les étapes. J’ai personnellement pas mal galéré avant de trouver au détour d’un échange sur un forum que si GZip est activé sur le serveur, alors Varnish ne gèrera pas les ESI. De plus, on a ici des fichiers statiques, il y a fort à parier que votre serveur envoie des entêtes de cache assez fortes dessus, donc après avoir fait une modif sur les configurations, pensez à faire un petit « touch index.html« , ça mange pas de pain 😉

Aller plus loin

On a effleuré le sujet rapidement, l’idée étant juste de présenter le concept, et de voir comment ça se met en œuvre concrètement. Ce système est intégré nativement dans Symfony2 (un « partial » sera alors traduit en <esi:incude /> correspondant) donc comprendre les bases des ESI vous aidera à comprendre comment fonctionne ce cache.

Il est évident qu’ici j’ai réduit les configurations au minimum. En pratique si la configuration de votre serveur HTTP restera probablement très light, il faudra bien sûr customiser celle de Varnish : pas besoin d’activer le parsing ESI dans le cas des fichiers non HTML par exemple. Et en allant un peu plus loin dans la documentation, on se rend compte à quel point la solution est extrêmement puissante et mériterait d’être envisagée dans toute architecture web qui se respecte 😉

11 réflexions au sujet de « Varnish & les Edge Side Includes pour faire du cache partiel de page »

  1. Louis

    J’ai lu avec attention ton billet.

    OK, les esi sont intéressant pour la rapidité. MAIS : pas sûr qu’en fait ce soir tant l’esi qui te fasse gagner du temps (par exemple entre un Varnish+Nginx avec esi et un Varnish+Apache). A mon avis, ce qui te fait réellement gagner du temps, c’est le fait que tu ne démarres pas le process Apache (en utilisant Nginx, qui est beaucoup plus léger). En effet, le fait que tu fasses un appel au serveur Nginx via esi démarre quand même le process. Du coup, à ce niveau, mieux vaut avoir un serveur rapide plutôt qu’un lourd. Après, je ne suis pas sûr que ça prenne vraiment beaucoup plus de temps de générer la page. Le plus gros du temps consommé est vraiment le démarrage du serveur (a mon avis).

    Répondre
  2. naholyr Auteur de l’article

    Je crois qu’il y a des confusions dans ton commentaire Louis… Tu ne dois pas avoir compris le contexte : on a une page dont seule une petite portion est *vraiment* mise à jour. L’idée est donc de ne pas calculer le contenu de toute la page, mais plutôt qu’une instance de cache (un proxy comme varnish) puisse la mettre en cache toute entière, *sauf* la portion qui nous intéresse.

    C’est à ça que servent les ESI. Ils ne servent pas à accélérer directement une page.

    De même, quand tu parle de « démarrer » le serveur, de quoi parles-tu vraiment ? On ne redémarre pas le serveur à chaque requête !! Et si tu parles du temps de connexion au serveur, il est totalement nul puisque dans cette archi Varnish et le serveur http sont soit sur la même bécane, soit sur un LAN (fibré).

    Répondre
  3. Antoine

    Ca me plait beaucoup ces petits ESI. Parce que, maintenant sur mon infra on ne cache que les images puisqu’elles sont statiques.
    Si je comprend bien varnish comprend les balises ESI nativement ?
    Oui, ce que dit l’ami Louis m’as l’air assez confu aussi.

    Répondre
    1. naholyr Auteur de l’article

      Oui c’est natif, pas de module spécifique l’instruction « esi; » est comprise d’office.

      Le seul piège c’est qu’il faut bien penser à désactiver la compression gzip du serveur qui est derrière, car Varnish ne s’amuse pas à décompresser la réponse, et donc dans ce cas n’interprétera pas les tags. Par contre derrière lui-même recompresse donc pas de perte à ce niveau :)

      Répondre
  4. Popy

    Du coup, c’est le proxy qui se mange la charge de la compression.
    C’est mignon étou, et ca devrait pas être très compliqué de passer tous les USER_INT d’un typo en esi :p

    Répondre
  5. Jean-Sébastien

    Popy, en même temps je pense que la compressions au niveau du serveur NGINX doit être plus performante que du côté su seveur Backend.

    Répondre
  6. eBuildy

    En fait ESI fait gagner du temps uniquement si votre « code » Php (par exemple) est « lent » (gros framework style Zend ou Symfony, accès base de données, appels API externes …) cela permet de mettre en cache le code HTML en résultant directement !

    Sur une boutique Prestashop, c’est juste …. hallucinant !!! Et le tout sans toucher au côté dynamique du site, c’est la tout l’intêret.

    Répondre
  7. Ping : Optimisation Web PHP : des caches à tous les niveaux « Le blog PHP de Nicolas Hachet – Développeur Web – Lead dev PHP MySQL

  8. Ping : Faites chauffer votre cache - ⚡ Nicolas Hodin

  9. Ping : Faites chauffer votre cache | ⚡ Nicolas Hodin

Laisser un commentaire