Varnish 3 : booster le nombre de hits



  • Dans cet article, nous allons voir différentes solutions pour augmenter le nombre de hits sur votre cache Varnish. Le but recherché est qu’un maximum de requêtes soient servies depuis le cache plutôt que du backend généralement moins performant. On pourra également essayer de réduire le nombre d’objets en cache et donc l’utilisation mémoire (ou disque) de Varnish.

    Il est important de savoir que sans configuration particulière, une page avec un cookie ne sera pas cachée. Cette page sera donc toujours servie du backend. Autre exemple : si votre site répond à deux URLs différents (www.monsite.fr et monsite.fr), c’est deux objets différents en mémoire. Le premier utilisateur de www.monsite.fr va être servi du backend et le second du cache. Mais le 3ème utilisateur qui lui aura demandé monsite.fr (et donc le 1er à demander cet URL) sera servi du backend.

    Il est donc important de faire un minimum de configuration pour augmenter le nombre de hits, mais aussi diminuer le nombre d’objets en mémoire.

    Augmenter le TTL de vos objets

    L’idéal serait d’augmenter le TTL au niveau de votre backend. Si ce n’est pas possible, vous pouvez le faire plus globalement au niveau de la configuration VCL de votre serveur Varnish.

    Par exemple, pour mon répertoire “images” qui n’est pas régulièrement mis à jour, je décide de forcer le TTL à 2 jours :

    sub vcl_fetch {
        if (req.url ~ "^/images/") {
            set beresp.ttl = 2d;
        }
    }
    

    Augmenter le TTL à un risque : si vous mettez à jour une image dans ce répertoire, la nouvelle version ne sera pas prise en compte avant l’expiration du TTL. Il faut alors purger du cache cet objet : voir l’article Purger le cache de Varnish 3.

    Ignorer/Supprimer des cookies

    Si une requête arrive avec un cookie, Varnish passera automatiquement la requête au backend. Si votre backend répond avec un cookie, l’objet ne sera pas caché. Clairement, dans ces cas-là, il n’y aura pas de hits. Par exemple WordPress va poser un cookie général sur l’ensemble des pages. Il est possible de le retirer sauf pour la partie authentifiée du site :

    # On supprime les cookies que le client envoie.
    sub vcl_recv {
    if (!(req.url ~ "wp-(login|admin)")) {
        unset req.http.cookie;
        }
    }
    
    # On enlève les cookies posés par WordPress.
    sub vcl_fetch {
    	if (!(req.url ~ "wp-(login|admin)")) {
    		unset beresp.http.set-cookie;
    	}
    }
    

    Attention : dans le cadre de l’exemple avec WordPress, si vous avez un plugin ou un widget qui nécessite l’utilisation d’un cookie, il ne fonctionnera plus. Il faudra certainement adapter cet exemple pour votre configuration. Dans tous les cas, retirer les cookies posés par votre backend impose une excellente connaissance de l’application hébergée. Dans le cas contraire, le risque est d’enlever un cookie indispensable au fonctionnement du site.

    Normaliser les URLs

    Je donnais l’exemple en introduction : si votre site peut être accédé via monsite.com et www.monsite.com, c’est deux objets différents en cache. Pour y remédier :

    sub vcl_recv {
    	if (req.http.host ~ "^(www.)?monsite.com") {
      		set req.http.host = "monsite.com";
    	}
    }
    

    Normaliser l’entête Accept-Encoding

    Un serveur web est capable de servir du contenu compressé. Grâce à l’entête Vary, il est possible de demander au serveur qui cachera ce contenu de garder une version différente en fonction, par exemple, de l’entête Accept-Encoding. Votre navigateur va annoncer ce qu’il accepte avec par exemple cet entête :

    Accept-Encodign: gzip,deflate
    

    Un autre avec cet entête :

    Accept-Encoding:: deflate,gzip
    

    C’est la même chose… Mais pas pour Varnish qui cachera ici deux objets différents. Pour résoudre ce problème :

    sub vcl_recv {
      if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # pas de compression pour ces demandes
            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 {
            # unkown algorithm
            remove req.http.Accept-Encoding;
        }
      }
    }
    

    Dans cet exemple, l’entête Accept-Encoding sera fixé de préférence à gzip si le navigateur le propose. Les fichiers déjà compressés sont exclus…

    Normaliser les User-Agent

    Comme dans l’exemple précédent, il est possible de demander au serveur de cache de garder une version différente en cache pour chaque User-Agent (avec Vary: User-Agent). Au vu du nombre de User-Agent possible (fonction du navigateur, de l’OS, de la version de l’OS…), le nombre d’objets en cache peut augmenter très rapidement à l’inverse du nombre de hits ! Si vous n’avez qu’une version pour Firefox et qu’une version pour IE, vous pouvez normaliser cette entête de cette façon :

    sub vcl_recv {
      if (req.http.user-agent ~ "MSIE") {
        set req.http.user-agent = "msie";
      } else {
        set req.http.user-agent = "firefox";
      }
    }
    

    Conclusion

    Voilà un ensemble de pistes pour améliorer le nombre de hits de votre site. Il est important de connaître correctement le fonctionnement du site en backend pour pouvoir gérer au mieux son optimisation (surtout quand on commence à supprimer des cookies). Aidez vous des outils Varnish varnishlog et varnishstat pour observer le comportement de Varnish avec vos nouvelles règles.