Pages Menu
TwitterRss
Categories Menu

Posté par le 15 nov 2011 dans Astuces, Planet-Libre | pas de commentaires

Purger le cache de Varnish 3

Il y a deux solutions pour purger le cache Varnish : la purge “classique” et les “bans”. Je vais reprendre l’article de varnish-cache.org en rajoutant des exemples pour les différentes méthodes de purge. Mais d’abord, pourquoi purger le cache ? Tout simplement parce que vous avez (vous ou votre client), par exemple, mis à jour une image, une page de votre site et qu’il faut alors purger le cache afin de fournir la dernière version de la page. Dans le cas contraire, tant que le TTL de l’objet (de la page, de l’image…) n’est pas atteint, Varnish ne vérifiera pas s’il y a une version plus récente sur le backend et livrera un contenu “périmé”. Il est donc important d’avoir une méthode manuelle et automatique pour purger votre cache.


 

HTTP Purges

C’est la méthode classique et la plus facile à mettre en oeuvre. Vous allez pouvoir, via une requête HTTP, purger un url du cache. L’inconvénient est que si vous avez, par exemple, 10 images à purger, il faudra faire 10 requêtes de purge pour invalider toutes les images. Pour autoriser la purge via HTTP, modifiez votre configuration VCL en vous inspirant de cet exemple :

acl purge {
        "localhost";
        "192.168.55.0"/24;
}

sub vcl_recv {
        # allow PURGE from localhost and 192.168.55...

        if (req.request == "PURGE") {
                if (!client.ip ~ purge) {
                        error 405 "Not allowed.";
                }
                return (lookup);
        }
}

sub vcl_hit {
        if (req.request == "PURGE") {
                purge;
                error 200 "Purged.";
        }
}

sub vcl_miss {
        if (req.request == "PURGE") {
                purge;
                error 200 "Purged.";
        }
}
  • On commence par définir une liste d’ACL. Attention à la syntaxe : le masque de réseau est en dehors des guillemets.
  • La routine vcl_recv est appelée quand une requête HTTP est reçue. Si la méthode demandée est PURGE et si le client fait bien parti des ACLs, on demande à Varnish de regarder la présence de l’objet dans le cache.
  • Si l’objet est présent, c’est la routine vcl_hit qui est utilisée. On va alors purger l’objet du cache (dans varnish 2.x, on fixait le TTL à 0).
  • La routine vcl_miss est nécessaire pour purger toutes les variantes définies par “Vary” que peut avoir un objet.

Pour purger un objet du cache, on utilisera alors la syntaxe suivante :

PURGE / HTTP/1.0
Host: example.com

On purge ainsi la page d’index du site example.com. On peut aussi utiliser curl comme dans cet exemple :

curl -X PURGE http://example.com/
 

Bans

Les bans vont vous permettre d’empêcher Varnish de servir du contenu du cache. Les bans ne sont pas permanents, ils sont utilisés pour supprimer du contenu déjà en cache en comparant les nouveaux hits aux bans. Cette deuxième solution à l’avantage de pouvoir utiliser des filtres. On peut placer un ban en filtrant, via une expression régulière ou via une égalité, sur une des variables suivantes : req.url, req.http.*, obj.http.*. Cette méthode est nativement disponible via le CLI. Dans l’exemple suivant, on purge toutes les images png :

ban req.http.host == "example.com" && req.http.url ~ "\.png$"

Vous pouvez également utiliser dans le CLI la fonction ban.url qui correspond à un ban req.http.url ~ :

ban.url example.com

Pour reproduire le fonctionnement de HTTP Purge, c’est à dire pouvoir via une méthode HTTP purger un url, rajoutez ce bloc :

sub vcl_recv {
        if (req.request == "BAN") {
                # Same ACL check as above:
                if (!client.ip ~ purge) {
                        error 405 "Not allowed.";
                }
                ban("req.http.host == " + req.http.host +
                      " && req.url == " + req.url); # attention : il faut un espace avant le && !!

                # Throw a synthetic page so the
                # request won't go to the backend.
                error 200 "Ban added with req.http.host == " + req.http.host + " && req.url == " + req.url";
        }
}

Pour faire un ban de l’index du site example.com :

curl -X BAN http://example.com/

Les bans sont ajoutés à une liste (ban.list ou purge.list avec Varnish 2.x). Quand il y a un HIT d’un objet, tous les nouveaux bans depuis le HIT précédent seront évalués. On peut vérifier la liste des bans via la commande ban.list dans le CLI :

ban.list
200        
0x7f0bdc416e80 1321199411     0 	req.http.host == example.com && req.url == /

Dans cette liste on retrouve :

  • L’id du ban.
  • Le timestamp du ban.
  • Le nombre d’objets pour lesquels la règle a été vraie (avec éventuellement G pour Gone en préfixe si le ban n’est plus valide).
  • Le filtre du ban.

Si vous avez 50 règles de bans et 10 objets en mémoire, il va falloir tester les 10 objets avec ces 50 règles avant de les retirer de la liste ! Si un objet n’est jamais accédé, la liste n’est jamais nettoyée de ces 50 règles (jusqu’à que le TTL de l’objet en question arrive à expiration : les bans qui sont plus vieux que le plus vieux des objets en cache sont automatiquement supprimés) ! Une liste de bans importante peut impacter les performances de Varnish (ce qui peut être rapidement le cas si vous avez beaucoup d’objets avec un TTL important). Pour résoudre ce problème, il faut utiliser ban lurker (activé par défaut depuis Varnish 3.0).


ban lurker

Le but de ban lurker est simple : un thread dédié pour parcourir l’ensemble des objets en cache et vérifier si l’un d’eux correspond à la ban.list. Quand un objet correspond à l’une des règles, il est immédiatement supprimé. Mais cette solution à un tout petit défaut : elle ne permet de travailler que sur des objets déjà dans le cache, en dehors de toute requête puisque dans un thread indépendant. Pour que votre ban soit compatible avec ban lurker, il faudra alors se passer de l’utilisation du filtre sur req.* (les exemples précédents sont donc incompatibles avec ban lurker, y compris la fonction ban.url).
Heureusement, une solution de contournement consiste à stocker l’url dans l’objet mis en cache :

sub vcl_fetch {
  set beresp.http.x-url = req.url;
  set beresp.http.x-host = req.http.host;
}

sub vcl_deliver {
  unset resp.http.x-url; # Pour cacher cette en-tête au client
  unset resp.http.x-host;
}

On peut maintenant profiter de bans compatibles avec ban lurker et qui utilisent la correspondance d’url en rajoutant dans le vcl_recv :

if (req.request == "BANURL") {
                        ban("obj.http.x-host == " + req.http.host +
                      " && obj.http.x-url ~ " + req.url);
                      error 200 "Ban added for host " + req.http.host + " and URL " + req.url;
                }

Pour purger l’ensemble des objets du site example.com :

curl -X BANURL http://example.com

On obtient le ban suivant qui sera traité par ban lurker :

0x7f0bdc416e80 1321199411     0 	obj.http.x-host == example.com && obj.http.x-url ~ /

Vous pouvez adapter ce VCL basique selon votre besoin. Il est également possible d’utiliser le CLI et de purger des objets via obj.http.x-url en fonction d’une expression régulière plus complète.

Pour désactiver ban lurker, utilisez l’option ban_lurker_sleep dans le CLI Varnish :

param.set ban_lurker_sleep 0

Pour le réactiver, il suffit de lui donner une valeur différente de 0, 0.01 étant sa valeur par défaut. Rappel : par défaut, ban lurker est désactivé sur les versions 2.x.

Poster une réponse

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


2 + deux =

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">