Niveau : intermédiaire
Nous avons un serveur web, un accélérateur PHP, un serveur SQL, possiblement un reverse-proxy de type Nginx, et le tout ronronne tranquillement.
Le framework du site est assez lourd. Toutefois les machines sont puissantes, et les pages sont générées en une ou deux secondes, ce qui est tout à fait acceptable pour le visiteur.
C'est ce que j'appellerais une architecture "honnête", ou encore "you get what you pay for".
Toutefois, s'il y a des pics de fréquentation, si le marketing décide d'organiser une campagne de communication sans vous prévenir, si votre site commence à devenir viral, par un bon billet Twitter ou des partages Facebook, son accessibilité risque de se dégrader rapidement.
Les temps de réponse d'un site croissent exponentiellement et non pas linéairement, par rapport au nombre de visiteurs : plus les serveurs seront sollicités, et plus les temps de réponse vont se dégrader.
Les visiteurs vont s'énerver lorsque leur page ne s'affichera pas assez rapidement, et vont encore plus charger l'infrastructure, qui s'écroulera.
Mon expérience dans le domaine de l'hébergement web m'a appris qu'une architecture "honnête" ne suffit pas pour absorber les pics de fréquentation, qu'il faut parfois savoir tricher avec l'architecture, ou encore "hyper optimiser", pour avoir une infrastructure solide, résiliente, capable d'encaisser.
C'est quelque part, d'un point de vue métier, laisser au site web la possibilité de dépasser les attentes, plutôt que de vouloir à tout prix le limiter, en se basant sur des objectifs de fréquentation fixés sur le papier ...
L'un des moyens les plus efficaces pour améliorer les performances des sites web, c'est Memcached !
Présentation du logiciel
Memcached est un service, tournant par défaut sur le port 11211, en TCP et UDP, accessible depuis les clients via un protocole réseau très simple.
Le logiciel n'est pas un "accélérateur PHP", et encore moins une base de données : c'est tout simplement un espace compris entièrement en RAM, qui peut stocker des clés et des valeurs, de façon temporaire.
Il fait partie de la mouvance "NoSQL".
A chaque clé est associée une valeur, ainsi qu'une date d'expiration.
Les opérations de lecture et d'écriture sont très performantes, puisqu'elles sont effectuées directement dans la RAM de la machine.
Memcached n'est pas un stockage persistant, les données peuvent être perdues à tout moment.
Et il est prévu, dans la nature même du logiciel, que les données seront perdues à un moment ou à un autre, soit parce qu'elles seront expirées, soit parce que Memcached sera plein et effacera les clés/valeurs par ordre d'ancienneté.
Pour la même raison, il n'y a aucun intérêt à ce que le service soit mis en haute disponibilité.
Il peut y avoir plusieurs services installés sur plusieurs machines, et alors les données seront distribuées. Mais pas redondées, puisqu'elles sont supposées être temporaires.
Sur une architecture distribuée, si l'un des services tombe, les données seront considérées comme perdues, et le logiciel devra s'en passer. S'il venait à régénérer ces données, elles seront stockées aléatoirement sur les services Memcached restants, possiblement à la place d'autres données, plus anciennes.
Avantages
Nous sommes censés parler de haute disponibilité, de redondance, et là, l'auteur nous présente un logiciel qui ne fait ni l'un ni l'autre, qui plus est, atteint de la maladie d'Alzheimer, puisqu'il perd ses données ... ("forgetting data is a feature")
Pourquoi ?
Le but de Memcached n'est pas de stocker des données, mais de stocker des données temporaires.
Et il le fait formidablement bien :
- le protocole est très léger
- le service peut être utilisé par n'importe quelle machine du réseau
- il ne fonctionne qu'en RAM, donc est extrêmement performant
- il peut être distribué sur plusieurs machines
- il est, par définition, capable de supporter toute perte de données, y compris dans leur intégralité
Il ne faut pas oublier que nous avons l'habitude d'utiliser des serveurs web et SQL pour nos sites web. Ces serveurs sont aujourd'hui très rapides, mais les frameworks de plus en plus lourd et complexes.
A chaque fois qu'une page web est construite par exemple, le serveur web lit un fichier, qui en appellera possiblement des centaines d'autres, tous lus sur disque; le tout sera compilé, des calculs seront faits, ensuite des requêtes seront faites aux bases de données, qui elles-mêmes feront des lectures / écritures sur disques, qui renverront les résultats, qui seront de nouveau interprétés, et ouf, une page web sera générée ! Et ensuite, pour "accélérer" la prochaine demande, la page sera stockée sur disque dur, en guise de cache.
C'est extrêmement lourd, ça demande du processeur, de la RAM, du réseau, et aussi des entrées / sorties disque.
N'est-il pas aussi étonnant de stocker le cache, censé accélérer les traitements, sur l'élément le plus lent de toute l'infrastructure, à savoir les disques ?!
On m'a pourtant toujours dit que le disque était l'élément le plus lent dans un ordinateur ...
Ce que propose Memcached, c'est de prendre un raccourci, en stockant les variables, les pages, bref, tout ce que l'on pourrait trouver dans un cache, en RAM.
Il y a des logiciels, notamment les "accélérateurs php" comme Xcache, qui stockent eux aussi les données en RAM. En quoi se différencie Memcached ?
Les logiciels comme Xcache font très bien leur travail. Ils ont toutefois un grand désavantage par rapport à Memcached : ils stockent le cache dans la mémoire locale de l'ordinateur. Si l'application fonctionne sur deux serveurs ou plus, ils ne pourront que travailler indépendamment les uns des autres, alors que l'on veut qu'ils travaillent ensemble.
Memcached offre donc une "RAM partagée", en réseau.
Concrètement, nous pourrons y stocker les données des sessions par exemple (c'est de loin la solution la plus performante, comparativement au NFS ou à MySQL), certaines variables PHP, et les caches de page des sites (si l'un des serveurs s'est donné la peine de calculer une page, autant que tous les autres en profitent)
Puisqu'il permet d'alléger les traitements applicatifs lourds (en temps processeur, en RAM, en E/S), et même s'il est spécialisé, il est beaucoup plus rentable, en terme de performances / prix, qu'un serveur web ou SQL supplémentaire.
Qui utilise Memcached ?
S'il était expérimental il y a encore quelques années, il est aujourd'hui suffisamment mûr pour être utilisé par tous les acteurs de l'Internet à fort trafic: YouTube, Reddit, Zynga (Farmville), Facebook, Orange, Twitter, Tumblr, Flickr, Digg, Typepad, Wikipedia, etc.
Il est aussi proposé en tant que service par tous les leaders du Cloud Computing, Amazon et Microsoft Azure, en tête.
Le seul concurrent que je vois aujourd'hui à Memcached, c'est Redis, qui fonctionne sur le même principe (Twitter, Instagram, GitHub, CraigList, The Guardian, Blizzard, Digg, Disqus, StackOverflow, Flickr)
Avec quels langages puis-je utiliser Memcached ?
Memcached se veut généraliste, il n'est pas uniquement dédié au monde du web. Ses performances peuvent être mises au service de toute application qui a besoin de stocker des données temporaires.
Il est notamment compatible C, C++, PHP, Java, Python, Ruby, Perl, .Net.
En ce qui concerne les sites web, tous les frameworks un tant soit peu sérieux proposent des plug-ins Memcached : Zend, Wordpress, Joomla!, Drupal, Symfony, EasyPublish, Django, Prestashop, Magento ...
Quelques architectures types
Résilience
Tout d'abord, rappelons que Memcached n'hiérarchise pas l'importance des données. Pour lui, les informations de session ont la même importance que les caches des pages, par exemple.
Alors que les sessions sont plus importantes, du point de vue de l'administrateur : vous ne voulez pas qu'elles "sautent".
Il faut donc, autant que possible, que l'espace Memcached ne soit jamais plein, sinon, il va commencer à effacer des données, et pas forcément celles que vous souhaitez.
Ceci étant dit, le dimensionnement n'est pas si difficile que ça, puisque le service ne stocke par définition que des données relativement légères.
Il faudra cependant adapter sa taille aux données que vous allez y stocker, en laissant une petite marge pour le cas où il y ait une panne, ponctuelle.
Plus il y aura de services Memcached, plus cette marge pourra être réduite.
Si nous avons 2 Memcached, les données doivent pouvoir être toutes stockées sur 1. Il y aura besoin de 100% d'espace supplémentaire.
Si nous avons 10 serveurs Memcached, les données doivent pouvoir être stockées sur 9, donc chacun n'a besoin que de 11% d'espace supplémentaire.
Notons toutefois que si les sessions ne sont pas plus importantes, il y a un paramètre PHP qui permet d'avoir des duplications sur X serveurs : memcache.session_redundancy.
Ce mécanisme est similaire au RAID. Si nous avons 4 serveurs, nous pouvons par exemple ajouter le paramètre memcache.session_redundancy=5 (1 + nombre de serveurs).
Tant qu'il y aura un service Memcached encore actif, vous ne perdrez aucune session.
A condition que la mémoire ne soit pas pleine, bien entendu; puisque Memcached aura beau répliquer les sessions entre les nœuds, s'il doit effacer des données, il ne fera aucune distinction.
Une seule instance
Vous avez un serveur web dédié, et vous installez Memcached sur cette machine.
Les dialogues se font en localhost.
Autant utiliser Xcache et son Data Store, les performances seront légèrement meilleures.
Des instances sur des serveurs web, en load balancing
Là, il n'est plus possible de passer par Xcache (ses données ne pourront être partagées entre plusieurs serveurs).
Imaginons que nous avons quatre serveurs web, et que l'on alloue 1GO au service Memcached sur chacune des machines.
Nous disposerons alors de 4GO de stockage RAM, distribué sur quatre serveurs. Nous y stockons sessions, variables, caches de pages, qui seront partagées par les quatre serveurs.
Si l'un des serveurs tombe en panne, nous perdons un 1/4 des données.
Si vous avez bien réglé memcache.session_redundancy, aucune session ne "sautera", et les serveurs web auront à régénérer 1/4 des caches de page.
Vous aurez une augmentation ponctuelle de la charge des serveurs web, certaines pages qui vont être plus longues à servir, mais aussitôt qu'elles auront été régénérées, les choses rentreront rapidement dans l'ordre.
Les serveurs web vont consulter chacun des Memcached, il y aura donc un trafic "horizontal" entre les machines. Un peu à la manière d'une grille ("grid computing").
Le débit dépendra de la quantité de données stockées par les applications, et de la fréquence à laquelle elles y feront appel.
Des instances dédiées
Nous pouvons aussi installer Memcached sur des serveurs dédiés. C'est ma solution préférée.
J'y vois un certain nombre d'avantages :
- les opérations cpu/ram ne vont pas "vampiriser" les ressources des serveurs web
- les problèmes de performances vont être plus faciles à diagnostiquer
- d'un point de vue infrastructure, il y aura des pools applicatifs séparés, plus faciles à gérer
- ... et plus faciles à sécuriser !
- vous pourrez dépanner un des clients, dont le site est trop lent, en lui proposant une instance Memcached dédiée
Toutefois, selon l'endroit de votre réseau où seront placés les serveurs Memcached, le trafic "vertical" va s'intensifier.
Imaginons que vous avez 4 baies 42U dédiées à l'hébergement web. Vous avez une trentaine de serveurs 1U dans chacune des baies, avec 2 switches 1U, pour le failover.
Et vous placez 4 serveurs dédiés à Memcached dans un autre baie, utilitaire, avec un certain nombre de services partagés par l'infrastructure.
Cela voudra dire que le trafic de Memcached passera par l'uplink des switches, entre les baies, et que la baie utilitaire devra supporter le trafic Memcached cumulé, arrivant des baies d'hébergement web, en plus des autres serveurs qui pourront y avoir été placés.
Dans ce cas-ci, il vaut mieux que les uplink des baies soient plus rapides que les connections serveurs.
Si vos serveurs font du Gigabit Ethernet, les interconnexions entre les baies ont tout intérêt à être en 10 Gigabits.
C'est de toute façon la topologie classique à l'heure actuelle, vu que les switches 10GbE sont devenus très abordables.
Mais si votre réseau n'est pas à jour, il vaut donc mieux prendre cet élément en compte ...
Il est également possible de "partitionner" vos serveurs Memcached, comme vous le feriez pour des bases de données. Par exemple, 30 serveurs web qui tournent sur 3 instances, 30 autres qui tournent sur 3 instances différentes, etc.
La topologie de votre infrastructure devra avant tout être adaptée à vos applications, et aux moyens dont vous disposez !
Avertissements sur la sécurité
Memcached a été conçu pour être performant à l'extrême, c'est pour cela qu'il utilise un protocole très léger, qui peut fonctionner en UDP ou TCP.
Il n'a donc pas de mécanismes de sécurité intégrés, à part le fait qu'il écoute par défaut sur localhost. Il écoute donc sur toutes les interfaces si l'option est désactivée.
Il ne doit pas tourner sur un serveur avec une IP publique, sinon, des intrus pourraient facilement avoir accès son contenu (sauf s'il y a un firewall correctement configuré, bien-sûr).
Il y a eu un certain nombre de fuites, en très grande partie dues à de petites sociétés qui avaient rajouté des instances Memcached à leur Cloud, sans penser à les sécuriser ...
Un peu dans l'optique "on vient de découvrir un logiciel il y a 5 minutes, il a l'air de marcher, et si on le mettait en production ?! LOL"
Dans le cas où Memcached tourne sur des serveurs web, pensez bien à restreindre son accès au réseau local, via un firewall.
S'il tourne sur des serveurs dédiés, c'est un avantage, puisque seul le réseau local peut y avoir accès.
Ce qui ne nous empêche d'ailleurs pas de mettre des sécurités supplémentaires en place, comme par exemple un firewall IPTables local, sur lequel vous autoriserez les adresses IPs pouvant accéder au serveur, au cas par cas.
Mise en œuvre de Memcached
Installation
Dans mon exemple, j'installe Memcached sur deux serveurs, 192.168.0.81 et 192.168.0.82.
Sur les serveurs Memcached :
apt-get install memcached libmemcached-tools
Editer la configuration du service vim /etc/memcached.conf :
Remplacer -m 64 par -m 1024 (par défaut, Memcached travaille sur 64MO de RAM, nous voulons dans notre exemple 1 GO)
Commenter si besoin le paramètre -l 127.0.0.1 (si nous voulons que memcached écoute en réseau)
Redémarrer le service :
/etc/init.d/memcached restart
Sur les serveurs web qui devront accéder au service :
apt-get install php5-memcache
Interfacer les sessions PHP avec Memcached
Editer votre fichier de configuration PHP sur les serveurs web vim /etc/php5/apache2/php.ini :
- Commenter la ligne "session.save_handler = files"
- Ajouter la ligne "session.save_handler = memcache"
- Commenter la variable actuelle "session.save_path", utilisée pour le chemin du stockage des sessions
- Ajouter la suivante, pour les deux serveurs :
session.save_path = "udp://192.168.0.81:11211?persistent=1&weight=1&timeout=1&retry_interval=15,udp://192.168.0.82:11211?persistent=1&weight=1&timeout=1&retry_interval=15"
- Ajouter les lignes suivantes, spécifiques au module Memcached
; permet d'avoir les clés indiquées sur tous les serveurs
memcache.hash_strategy = consistent
; force php à lire/écrire sur un autre serveur en cas de défaillance du premier appelé
memcache.allow_failover = 1
; nb de serveurs memcached + 1
memcache.session_redundancy=3
Redémarrer Apache pour que les paramètres soient pris en compte :
/etc/init.d/apache2 restart
Vérifications
Les serveurs Memcached devraient maintenant stocker les sessions PHP.
Logguez-vous dans n'importe quel applicatif web (il semblerait que PHPMyAdmin ait du mal avec Memcached, si vous l'utilisez).
Sur les serveurs memcached, vous pouvez consulter la liste des variables avec la commande suivante :
memcdump --servers 127.0.0.1:11211
6tfcthrshosrecpdr6udphiarvkg79o3.lock
6tfcthrshosrecpdr6udphiarvkg79o3
Vous devriez voire apparaitre votre session, sur les deux serveurs Memcached.
A noter que vous pouvez aussi consulter leur contenu, via la commande suivante :
memccat --servers 127.0.0.1:11211 6tfcthrshosrecpdr6udphiarvkg79o3
Benchmark
Utilisation sur la home de mon site Joomla!, un CMS plutôt complexe et lourd, que j'ai déjà configuré pour Memcached.
J'utilise ici un serveur bi-Xeon 1,86GHz, soit 8 cœurs au total
Sans cache : 1,31s le premier accès, 150ms les fois suivantes (grâce à l'accélérateur PHP)
Avec cache fichiers, sur NFS (ZFS, rapide) : 700ms le premier accès, 100ms les fois suivantes
Avec cache Memcached : 400ms le premier accès, 50-60ms les fois suivantes
Notons que dans mon cas, j'utilise une grosse machine dédiée, et que je suis actuellement le seul visiteur sur mon site.
Plus il y aura de visiteurs sur le site, et moins la machine aura à disposition de ressources pour générer une page. En production, il n'est pas rare que ce type de site dépasse 5 secondes pour une page.
Et c'est alors là que Memcached prend tout son intérêt !
Conclusion
Memcached est un outil formidable, qui répond aux problématiques auxquelles nous sommes confrontés lorsqu'on fait du load balancing web.
Notamment à celle du stockage des sessions en réseau, pour laquelle le NFS est très peu adapté, car trop lent.
Il permet aussi de GRANDEMENT améliorer les performances d'un site dynamique, pour peu que le framework permette de s'y interfacer (et la plupart proposent cette option)
Autant ne pas connaitre Memcached, ça peut se concevoir. Autant ne pas l'utiliser, alors qu'on le connait, relève presque de la faute professionnelle.
Le service est souple d'utilisation, vous pouvez l'ajouter à un serveur web déjà existant, ou en faire un service dédié.
Si vous travaillez pour un site / éditeur web, qu'il y a une équipe hébergement et développement fixe, vous pourrez facilement intégrer le service à votre infrastructure.
Si vous faites de l'hébergement web, et que vous n'avez pas la main sur le développement, vous aurez souvent à gérer des mises en ligne désastreuses, des sites qui ne sont pas passés par des tests de montée en charge, et qui sont atrocement lents.
C'est alors que vous pourrez proposer le service Memcached pour dépanner le client. Cela ne fera que renforcer votre valeur ajoutée !
Un exemple de l'utilisation de Memcached sur le CMS Joomla! :
Optimiser Joomla! (Memcached et divers)