Introduction au serveur de cache avec Squid 3.0 (partie 1/2)

#cache#performances#squid

Squid est un serveur cache qui peut être utilisé en tant que proxy ou reverse-proxy. Dans cet article, nous n’aborderons que l’aspect classique de proxy. La version de Squid présentée ici est la version 3.0.STABLE19.

Aujourd’hui, le nombre de personnes accédant à Internet est en constante augmentation. Pour répondre à cette demande grandissante, les Fournisseurs d’Accès à Internet (FAI) déploient de nouveaux équipements réseaux offrant de plus en plus de bande passante. De leur côté, les fournisseurs de contenu sont forcés d’utiliser des serveurs toujours plus puissants pour répondre à cette nouvelle charge.

Ces évolutions ne se font toutefois pas toujours de façon parallèle. Lorsque la capacité des serveurs est au rendez-vous mais que la bande passante est insuffisante, l’utilisateur ne bénéficie que d’un débit réduit et il est confronté à des problèmes de lenteur. Dans l’autre cas, lorsque la bande passante est importante mais que les serveurs ne sont pas assez puissants, ils peinent à répondre aux postes client et une fois encore, l’utilisateur peut constater des problèmes de lenteur.

Une réponse à ces deux problématiques réside dans l’utilisation de serveurs cache aussi appelés proxy cache. Il existe deux configurations principales pour un serveur proxy, chacune d’elle répondant aux problématiques évoquées ici. Dans la première, dite configuration proxy, le serveur a pour rôle de centraliser l’accès Internet des utilisateurs d’un réseau local : il sert de passerelle vers Internet. Il permet ainsi de servir plus rapidement les utilisateurs d’un réseau local qui ne bénéficieraient pas d’une bonne connexion avec l’extérieur. Dans le second cas de figure, le serveur est dit reverse-proxy. Il est utilisé pour recevoir les connexions provenant d’Internet vers un réseau local. Il permet alors de soulager la charge des serveurs et de sécuriser l’accès à des ressources.

Squid est l’un de ces serveurs cache et peut être utilisé en tant que proxy ou reverse-proxy. Dans cet article, nous n’aborderons que l’aspect classique de proxy. La version de Squid présentée ici est la version 3.0.STABLE19.

1. Qu’est-ce que Squid ?

Squid est un serveur cache libre et open source développé à partir de 1996 par l’équipe de Duane Wessels. Il est originaire d’un projet plus ancien débuté en 1990, le projet Harvest, développé au sein de l’université du Colorado. Squid est aujourd’hui distribué sous la licence GNU General Public Licence (GPL) et peut être installé sur différentes distributions Linux mais également sur plateformes Windows, Unix, Mac OS X, etc.

Squid est placé entre le poste client et le serveur qui délivre les pages, appelé aussi serveur source ou serveur d’origine. Son rôle principal est d’économiser de la bande passante et d’améliorer les délais de réponse aux utilisateurs. Pour ce faire, il stocke les ressources demandées afin de les resservir plus rapidement si elles sont demandées à nouveau par la suite. Il peut s’agir de pages Internet, d’images ou de vidéos : on parle alors plus facilement d’objet pour désigner les ressources mises en cache par le serveur.


Schéma de mise en place d’un serveur Squid dans un réseau local

Bien qu’il soit essentiellement utilisé avec HTTP, Squid supporte plusieurs protocoles :

  • HTTP/1.0 (le serveur est compatible avec un peu plus de 80% des nouvelles fonctionnalités HTTP/1.1).
  • FTP via HTTP pour le chargement et le téléchargement de fichier. La modification et la suppression à distance ne sont pas supportées.
  • ICP (Inter Cache Protocol), utilisé pour communiquer avec d’autres serveurs cache.
  • SSL pour les connexions sécurisées.

Selon les besoins, plusieurs serveurs cache peuvent être mis en place dans un réseau. Ces différents serveurs peuvent être amenés à échanger des données que certains auraient en cache mais pas d’autres. Pour cela, plusieurs protocoles peuvent être utilisés. Voici ceux qui sont supportés par Squid pour les échanges inter-cache :

  • HTTP : le protocole Web est ici utilisé par un serveur pour récupérer un objet depuis un autre serveur cache.
  • ICP : ce protocole permet de questionner un serveur cache voisin pour savoir s’il possède la ressource recherchée.
  • Cache Digests : ce protocole permet de questionner un serveur en utilisant une empreinte de l’objet recherché. Le serveur distant regarde alors dans son index s’il possède l’empreinte de la ressource demandée et répond positivement le cas échéant.
  • Simple Network Management Protocol (SNMP) : ce protocole est plutôt destiné aux administrateurs et permet d’accéder à différentes informations du serveur.

2. Pourquoi mettre en cache ?

En dehors des points évoqués dans l’introduction à savoir l’économie de bande passante et l’amélioration des délais de réponse, plusieurs raisons peuvent amener un administrateur réseau à mettre en place Squid dans son réseau local.

Les politiques de sécurité et de filtrage sont généralement un très bon argument pour la mise en place de Squid. Placé entre un réseau local et Internet, Squid peut empêcher certains utilisateurs d’accéder à des sites ou à des contenus jugés potentiellement dangereux ou nuisibles. Plus généralement, il peut bloquer l’accès complet à Internet si l’utilisateur n’a pas les droits requis pour s’y connecter.

Une autre justification de la mise en place de Squid peut résider dans l’abandon prématuré du téléchargement de ressources volumineuses. L’utilisateur peut volontairement ou accidentellement interrompre un téléchargement. Si le contenu incomplet n’est pas mis en cache, il faudra reprendre le téléchargement depuis le début la prochaine fois. Squid permet de remédier à ce problème et de reprendre un téléchargement abandonné sans tenir compte de l’utilisateur qui en fait la demande. Une dernière bonne raison de mettre certaines ressources Web en cache est la consultation en mode déconnecté. Certains sites, pour cause de maintenance ou de problèmes techniques, peuvent être temporairement indisponibles. Dès lors que leurs ressources ont déjà été consultées et mises en cache, elles sont disponibles via le serveur cache. En faisant par exemple une recherche Google, on observe que pour chaque résultat fourni par le moteur un lien vers la dernière version mise en cache est disponible. Il s’agit en quelque sorte d’un cliché du site à un instant donné.

3. Les différents types de cache

Avant de commencer à parler proprement de Squid et de son utilisation, il faut bien distinguer les différents types de cache qui existent et qui peuvent être sollicités lors d’un accès à une ressource. En effet, lorsque l’utilisateur tente de se connecter à un serveur distant pour récupérer une page, il peut, sans le savoir, passer par plusieurs machines intermédiaires et interroger différents serveurs de cache.

Le tout premier niveau de cache est géré par le navigateur Internet. Il s’agit d’un cache local et non partagé. Le comportement lié à ce cache local est propre à chaque navigateur. Il ne sera pas détaillé dans ce document.

Le second niveau de cache qui nous intéresse est celui qui fait l’objet de cet article, à savoir celui qui est géré par le proxy Web. Il est généralement partagé par les utilisateurs du réseau local qui se connectent à Internet à travers lui. Ce cache est administré par le responsable du réseau local.

Le troisième niveau de cache est celui maintenu par les différents reverse-proxy auxquels peuvent s’adresser un poste client. Ces serveurs de cache sont mis en place par les administrateurs des sites distants pour répondre au mieux à leurs utilisateurs et exploiter leurs serveurs le plus efficacement possible.

4. Comment Squid procède pour la mise en cache

Le fonctionnement de Squid est intimement lié au protocole HTTP. Ce dernier utilise les en-têtes HTTP pour relayer les requêtes du poste client et lui envoyer une réponse. Le contenu HTML des paquets n’est pas utilisé par Squid pour faire de la mise en cache.

La première activité de Squid est de relayer les requêtes clientes et de mettre en cache la réponse si celle-ci est éligible au cache. Pour savoir si la réponse peut être mise en cache, Squid analyse les données présentes dans l’en-tête HTTP. Voici les règles qui sont suivies pour décider de la mise en cache :

  • Si des instructions interdisant la mise en cache sont rencontrées (Cache-Control: private), la ressource n’est pas mise en cache.
  • Si la connexion est sécurisée ou authentifiée, la ressource n’est pas mise en cache.
  • Si aucune directive de validation n’est présente (Last-Modified ou Etag), la ressource n’est pas mise en cache.
  • Autrement, la ressource est considérée comme éligible au cache et Squid décide de la stocker.

Si Squid reçoit une requête qui a déjà donné lieu à la mise en cache de la ressource, celui-ci va valider la donnée afin de savoir si elle est assez récente et si elle peut être renvoyée à l’utilisateur en l’état ou bien si au contraire, elle est considérée comme trop ancienne et nécessite d’être redemandée au serveur d’origine.

Cette étape de validation s’appuie sur les directives d’expiration et de validation contenues dans l’en-tête HTTP (Expires, max-age, Last-Modified et Etag). Le serveur procède de la sorte :

  • Vérification de la validité de la ressource en cache à l’aide des directives d’expiration (Expires et max-age). Cette étape consiste en un simple calcul de date aboutissant à la péremption ou non d’un objet du cache. Si ces directives ne sont pas présentes, la réponse est considérée comme étant valide à tout moment.
  • Si la ressource est considérée comme encore valide, elle est renvoyée au poste client sans contacter le serveur source.
  • Si la réponse est périmée, une requête conditionnelle (If-Modified-Since ou If-None-Match) basée sur les directives Last-Modified ou Etag est envoyée au serveur source qui répond soit en envoyant la nouvelle ressource soit en envoyant un code HTTP 304-Not Modified.

5. Normes et Standards

5.1 Les requêtes éligibles à la mise en cache

Le protocole HTTP fournit de nombreuses commandes permettant au poste client de communiquer avec le serveur. Certaines d’entre elles ne nécessitent pas de mettre en cache la réponse du serveur. Squid distingue les différents types de requêtes qui transitent pour n’en traiter qu’une partie. Voici la liste des commandes HTTP qui peuvent aboutir à la mise en cache de la réponse serveur :

  • GET : permet de récupérer une ressource serveur.
  • HEAD : permet de récupérer des informations sur une ressource sans la retourner.
  • CONNECT : permet de préciser un proxy auquel se connecter.

A l’inverse, les commandes suivantes ne donnent pas lieu à une mise en cache par Squid :

  • OPTIONS : permet de récupérer les options de communication associées à une ressource ou les capacités d’un serveur.
  • TRACE : permet de demander au serveur ce qu’il a reçu pour analyser les données envoyées.
  • POST : permet d’envoyer des données au serveur.
  • PUT : permet d’envoyer un fichier vers le serveur (requiert un accès en écriture).
  • DELETE : permet de supprimer une ressource du serveur (requiert un accès en écriture).

Il est donc important de noter que les requêtes POST ne sont pas gérées par le cache, celles-ci pouvant modifier la représentation d’une ressource pour un utilisateur particulier. La recommandation du standard HTTP est même d’invalider une ressource Web mise en cache lorsqu’une requête POST est faite avec la même URL.

5.2 Les directives de cache HTTP/1.1

Afin de bien appréhender les différents aspects du cache HTTP, nous allons voir ici les différentes directives de cache HTTP/1.1 et comment Squid les interprète.

La directive principale de cache dans la version 1.1 du protocole HTTP est la directive Cache-Control. Elle peut prendre plusieurs options que nous allons voir en détail ici et qui influent directement sur le comportement du serveur cache.

Avant d’aller plus loin, ouvrons juste une parenthèse sur un aspect de terminologie. On distingue en réalité deux types de cache, les caches partagés et les caches privés. Les caches partagés permettent à n’importe quel utilisateur d’accéder à une ressource cachée par un autre utilisateur. Les caches privés quant à eux sont réservés à un unique utilisateur, on ne s’y intéressera pas dans cet article.

La directive de cache HTTP peut aussi bien être présente dans la requête que dans la réponse. Utilisée dans la requête, elle permet au poste client de piloter certains aspects du serveur cache en signifiant par exemple de ne retourner une réponse que si celle-ci est dans le cache. Dans la réponse, c’est le serveur source qui pilote le comportement du serveur cache. Il faut toutefois noter que l’administrateur est libre de redéfinir le comportement par défaut de Squid en ignorant certaines directives ou en les surchargeant. Ce type de configuration non conforme aux standards W3C peut amener des problèmes de sécurité en permettant la mise en cache de données sensibles. Il n’est donc recommandé de le faire que dans des cas très précis.

Dans une requête adressée par un utilisateur, la directive Cache-Control peut prendre les valeurs suivantes :

  • no-cache = « field name(s) »
  • no-store
  • max-age = delta-seconds
  • max-stale = delta-seconds
  • min-fresh = delta-seconds
  • no-transform
  • only-if-cached
  • cache-extension

Au sein d’une réponse serveur, les valeurs possibles sont les suivantes :

  • public
  • private
  • no-cache = « field name(s) « 
  • no-store
  • no-transform
  • must-revalidate
  • proxy-revalidate
  • max-age = delta-seconds
  • s-maxage = delta-seconds
  • cache-extension

On donne ici une brève description de chacune de ces options et de leur utilisation. Pour plus de détails sur le sujet, il est possible de consulter la RFC 2616 d’où sont issues la plupart de ces informations.

Pour les options disponibles dans la requête et la réponse HTTP :

  • no-cache : cette option utilisée dans la requête va forcer le serveur à recharger la page auprès du serveur d’origine. Quand cette option est présente dans la réponse, cela indique que la ressource doit être revalidée chaque fois qu’elle est redemandée.
  • no-store : cette option permet de ne pas stocker la réponse sur le disque. La réponse peut être mise en cache mais ne doit pas être enregistrée sur des volumes de stockage non volatiles. Cette option, lorsqu’elle est utilisée dans la requête, n’est pas encore supportée dans la version de Squid qui fait l’objet de cet article.
  • no-transform : cette option permet d’empêcher le serveur cache de modifier le paquet HTTP, que ce soit l’en-tête HTTP ou le contenu lui-même. Certains serveurs de cache convertissent ou compressent les données pour économiser de l’espace mémoire. A l’aide de l’option no-transform, ce type de proxy dit non transparent, peut être contraint à ne pas modifier la réponse.
  • max-age = delta-seconds : utilisée dans la requête du poste client, cette option permet de fournir une valeur (en secondes) correspondant à l’âge maximum accepté pour la ressource retournée par le proxy cache. Sauf si l’option max-stale est également fournie, cela signifie que le poste client ne désire pas recevoir de réponse périmée.

Lorsqu’elle est fournie par le serveur, cette option sert de validateur et implique que la ressource est éligible au cache. Une réponse HTTP avec une directive max-age ayant pour valeur 3600 indique par exemple au cache que la ressource peut être stockée et qu’elle pourra être considérée comme valide pendant une heure. Lorsque cette option a pour valeur « -1 », elle équivaut à l’option no-cache et indique au serveur qu’elle ne doit pas être stockée. Si la directive Expires (HTTP/1.0) est également présente dans l’en-tête HTTP, l’option max-age (HTTP/1.1) est utilisée en priorité.

  • cache-extension : en plus de ces options définies par les standards du W3C, il est possible de fournir dans la directive Cache-Control des paramètres élaborés spécifiquement pour une utilisation avancée des serveurs de cache. Le comportement des serveurs de cache peut ainsi être étendu. Les serveurs qui ne reconnaîtraient pas ces options particulières ne les traiteraient pas.

Pour ce qui est des options spécifiques à la requête :

  • max-stale = delta-seconds : permet d’indiquer au serveur de cache que le poste client est prêt à accepter une réponse éventuellement périmée mais dont le délai d’expiration n’excède toutefois pas la valeur passée en paramètre. Si aucune valeur n’est passée, toute réponse périmée est acceptée par le poste client.

Pour illustrer cette option, on suppose une ressource r avec comme paramètre max-age=3600 mise en cache à un instant t. Si à l’instant t + 4000, une requête est reçue pour la même ressource avec une directive max-stale=1000, le serveur de cache peut renvoyer la ressource périmée car celle-ci est périmée depuis 400 secondes seulement et le poste client est quand à lui prêt à recevoir une réponse périmée d’au plus 1000 secondes.

  • min-fresh = delta-seconds : permet d’indiquer au serveur de cache que le poste client est prêt à accepter toute réponse qui sera encore considérée comme valide dans la période passée en paramètre. A la réception de ce type de requête, si la ressource est présente dans le cache, le serveur additionne la valeur de l’option min-fresh à l’âge de la ressource et regarde si le total est inférieur à la valeur de l’option max-age. Si c’est le cas, la ressource est renvoyée au poste client, sinon, le serveur source est contacté.

Pour illustrer l’utilisation de cette option, supposons qu’une ressource r soit mise en cache à l’intant t avec comme paramètre max-age=3600. Cela signifie qu’à l’instant t + 3600 + 1, la ressource sera périmée. On considère qu’à l’instant t + 100 le serveur reçoit une requête pour cette même ressource avec une directive min-fresh à 1800. Cela signifie que le client exige une ressource qui sera valide pendant au moins 30 minutes. Le serveur effectue alors le calcul suivant t + 100 + 1800 et compare le résultat à l’âge maximum de la ressource soit 3600. La somme calculée par le serveur étant inférieure à l’âge maximal de la ressource, celle-ci peut être renvoyée au poste client. Dans le cas contraire, la ressource aurait dû être redemandée au serveur source. Cette option n’est pas encore totalement supportée dans Squid3 qui fait l’objet de cette étude.

  • only-cached : cette option permet de récupérer dans le cache une ressource uniquement si celle-ci est déjà présente dans le cache. Si ce n’est pas le cas, une réponse HTTP « 504-Gateway timeout » est renvoyée au poste client.

Au niveau de la réponse du serveur d’origine, les options disponibles pour la directive de cache sont les suivantes :

  • public : permet d’indiquer aux serveurs de cache que la réponse est éligible à la mise en cache (valable aussi bien pour les caches partagés que les caches privés).
  • private : cette option permet d’indiquer au serveur de cache que tout ou partie de la réponse est destiné à un unique utilisateur et que par conséquent la réponse ne doit pas être mise en cache. Cette option ne permet pas à elle seule d’assurer la confidentialité du relai, certains proxy cache peuvent ne pas respecter les standards et mettre en cache ce genre de données.
  • must-revalidate : cette option peut être utilisée par les serveurs source pour forcer la validation des données mises en cache. Cela permet d’éviter un comportement observé chez les serveurs de cache qui ignorent la directive d’expiration et qui diffusent du contenu périmé. Lorsqu’un serveur de cache rencontre cette directive, il doit revalider la ressource auprès du serveur source.
  • proxy-revalidate : cette option permet de réaliser la même chose que l’option must-revalidate à ceci prêt qu’elle n’est utilisée que par les serveurs de cache.
  • s-maxage = delta-seconds : cette option permet de combiner les propriétés des options max-age et must-revalidate. Le paramètre fourni permet de contrôler la date d’expiration de la ressource envoyée par le serveur et de forcer la revalidation par le serveur cache. Cette option surcharge les options Expires et max-age. Elle n’est pas totalement supportée dans la version de Squid qui fait l’objet de cette étude.

Pour plus d’informations au sujet des directives de cache, il est possible de se reporter à la RFC 2616 et au document de recette de Squid qui précise pour chaque préconisation du W3C le comportement de Squid observé. Ce document est disponible sur le site officiel de Squid.

5.3 Les « Etags »

Les Etags (Entity Tag) sont arrivés avec la version 1.1 du protocole HTTP. Ils ont été pensés afin d’améliorer le processus de validation qui était auparavant basé sur l’option Last-Modified pour envoyer une requête IMS (If-Modified-Since) au serveur source. Un Etag est en fait une empreinte (ou hash) qui est associée à une ressource et qui permet de l’identifier de manière plus ou moins unique. Celui-ci est généré par le serveur source et apporte un autre mécanisme de détection des modifications basé sur l’utilisation des directives HTTP If-Match et If-None-Match.

Il existe deux types d’Etag, les premiers sont dits ‘forts’, les autres ‘faibles’. Les Etags forts permettent de certifier que le contenu téléchargé est identique au bit près. A l’inverse, les Etags dits faibles sont utilisés pour identifier la valeur sémantique d’un contenu. Ils peuvent donc représenter deux contenus différents, c’est à l’administrateur du serveur d’origine de décider si un contenu a significativement évolué et nécessite le recalcul de son empreinte. Par convention, un Etag ‘faible’ commence généralement par la chaîne « W/ ». Dans la version 3 de Squid, le support des Etags n’est pas encore complet. Squid est capable de traiter les requêtes clientes contenant les directives If-Match et If-Non-Match de l’en-tête HTTP et de détecter si l’Etag de la version en cache est différent de celui passé dans la requête afin de décider si la ressource doit être récupérée auprès du serveur d’origine. Toutefois, les requêtes générées par Squid pour la validation des données en cache auprès du serveur d’origine ne se basent pas sur les Etags mais toujours sur la directive Last-Modified.

Dans cette première partie consacrée à la présentation de Squid, nous avons décrit le rôle du serveur de cache et son principe de fonctionnement. Nous avons également parcouru les grandes notions de cache HTTP préconisées par les standards du W3C. La suite de cet article, bientôt en ligne sur le site d’Osaxis, traitera de l’installation et de la configuration de Squid et présentera certains des aspects de cache vus ici à travers des exemples concrets d’utilisation.