Accélérer des sites web avec nginx et memcache

site_internetLes performances de sites web sont un sujet très complexe qui peut être abordé sous de nombreux angles. Ce sujet est tout à fait critique du fait que les moteurs de recherche prennent en compte cette métrique pour le référencement des sites. Dans le cas de sites e-commerce, les performances peuvent influer assez fortement le taux de conversion des visites en achat comme l’a montré Amazon.

Afin d’optimiser les performances d’un site, il est souvent préférable de s’intéresser au code et au fonctionnement interne du site afin de détecter les améliorations possibles. Mais, parfois, pour des raisons diverses et variées, vous n’avez soit pas la possibilité soit pas les connaissances vous permettant de mettre les mains dans le code. C’est à cette situation que nous allons nous intéresser aujourd’hui.

Le concept

L’idée est d’utiliser nginx en tant que serveur HTTP frontal et de le coupler à memcache en tant que système de mémoire cache ultra-rapide. Cette manipulation se déroulera en deux parties. Tout d’abord, il faut configurer nginx pour qu’il aille chercher les pages et contenus statiques dans memcache. Ensuite, il faudra remplir la base de données de memcache en pages HTML et contenu statique.

En réussissant à faire cela, nous allons pouvoir fortement réduire le temps de chargement de chaque page mais aussi accroitre considérablement la quantité de requêtes que notre infrastructure pourra traiter en parallèle. Ceci s’explique assez simplement par le fait qu’il est beaucoup moins couteux d’aller chercher une information en base de données stockée en mémoire que d’exécuter toute une pile applicative interfacée avec une base de données type SQL.

Installation et configuration de memcached

L’installation du démon memache, à savoir memcached, est particulièrement simple. Vous pouvez utiliser votre gestionnaire de paquet préféré. Le fichier de configuration est très simple à utiliser, il suffit d’indiquer la quantité de mémoire que vous souhaitez allouer memcached ainsi que l’IP à laquelle vous l’attacherez.

Dans mon cas, j’ai installé memcached directement sur le serveur frontal et l’ai rendu accessible sur une IP interne firewallée de sorte à ce que seuls les serveurs concernés y aient accès. Vous trouverez un exemple de fichier de configuration ici.

Configuration de nginx

En ce qui concerne la configuration de nginx, vous trouverez un exemple ci-dessous.

[code language= »text »]server {
listen 80;
server_name sitetroprapide.fr;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

location / {
if ($request_method != GET)
{
return 500;
}
default_type text/html;
add_header "Content" "text/html; charset=utf8";
charset utf-8;
set $memcached_key $http_host$uri;
memcached_pass 10.1.1.1:11211;
error_page 500 404 405 = @bypass;
}

location @bypass {
proxy_pass http://sitetroprapide-prod;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
client_max_body_size 20M;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

}[/code]

Les parties spécifiques à memcache sont les lignes 15 à 17. La ligne 15 avec la directive set est probablement celle qui mérite le plus votre attention. En effet, cette ligne définit la « clé » que nginx ira demander à memcache afin de pour la distribuer aux clients. En fonction des sites que vous souhaitez héberger et du type de contenu, vous devez paramétrer cette ligne de sorte à ce que deux contenus différents n’aient pas la même clé sinon il y aura conflit. La configuration proposé utilisera des clés de type « www.sitetroprapide.fr/ » et « www.sitetroprapide.fr/page-1.html ». La ligne 16 avec la directive memcached_pass correspond au serveur memcache que vous souhaitez utiliser.

La ligne 17 avec la directive error_page permet de renvoyer la requête dont le contenu n’a pas été trouvé dans memcache vers les serveurs applicatifs. Grace à cette directive, vous aurez également la possibilité de générer des erreurs afin d’éviter le cache memcache dans certains cas comme c’est le cas pour les requêtes autres que des GET (cf. le block if à la ligne 8).

Mettre les données dans memcache

Vous l’aurez probablement compris, les étapes proposées plus haut permettent à nginx d’aller chercher du contenu dans memcache mais pas d’en stocker dedans. Afin de mettre les données dans memcache, vous aurez plusieurs solutions.

Tout d’abord, vous pouvez modifier votre site afin qu’il stocke le contenu des pages dans memcache. Cette solution est la plus élégante mais nous force à modifier l’application ce que nous souhaitions éviter depuis le début.

Ensuite, une autre solution est de charger les pages du site dans memcache en utilisant un script externe. C’est la solution que j’ai choisi. Vous trouverez un exemple de script que j’ai développé pour l’occasion en Python. Ce script insère dans memcache toutes les pages qui ont lien à partir de la page d’accueil ainsi que tous les contenus associés. Ce n’est probablement pas un exemple d’élégance pour du développement Python mais ça fait ce que je voulais lui faire faire.

Problématiques

Avant de vous montrer un exemple des bénéfices tirés de cette configuration, il me parait indispensable de parler des problématiques induites.

Lorsque vous chargez une page avec une clé dans memcache, le serveur frontal servira toujours cette page sans jamais aller consulter vos serveurs applicatifs. Cela signifie que si vous servez des pages ayant la même URL que vos utilisateurs soient identifiés ou non, memcache distribuera systématiquement la même page. Dans ce cas-là, il faudra adapter la configuration nginx afin de ne pas aller chercher les informations dans memcache si le cookie d’authentification est présent.

Pour résumer, il ne faut pas perdre de vue ce que fait cette configuration car ce n’est pas une solution miracle. C’est une solution très bien adaptée aux sites tels que des sites d’actualité où seulement une faible proportion des utilisateurs sont identifiés. Elle peut également s’appliquer aux sites de e-commerce afin d’accélérer le chargement des pages pour les nouveaux utilisateurs qui ne se sont pas encore identifiés par contre dès qu’ils s’identifieront, les performances redeviendront standards.

Résultats

Voici deux exemples de graphiques présentant le temps de chargement des pages pour deux sites sur lesquels j’ai implémenté cette configuration. L’amélioration est assez flagrante.

resultat2resultat1

Le script de mise à jour du contenu est exécuté toutes les heures afin d’éviter d’impacter trop fortement les pages non mises en cache. C’est une fréquence de mise à jour acceptable car ce sont des sites relativement peu mis à jour mais cela va dépendre en fonction de cas. Il reste encore des améliorations à faire au niveau du script afin de pouvoir fournir une interface permettant de rafraichir le cache de manière plus automatisée.

Bilan

Pour résumer, il est possible d’accélérer de manière très significative le chargement des pages web en utilisant nginx coupé à memcache. Néanmoins, cette configuration nécessite un mécanisme de chargement des données qui colle le mieux possible au type de site mis en cache. Il faudra donc se pencher sur chaque cas afin d’étudier les possibilités de mise en cache et de trouver la meilleure approche à adopter.

Les architectures web – le serveur dédié

icone-projet-webCet article fait suite à l’introduction sur les architectures web. La dernière fois, nous nous sommes intéressés aux composants d’une architecture web ainsi qu’à une installation basique mais limitée à un unique serveur virtuel. Nous allons maintenant nous placer dans une nouvelle situation plus exigeante. En effet, le site que vous hébergiez dans un premier temps sur un serveur virtuel est à l’étroit. Votre site a gagné en popularité et votre serveur virtuel ne vous suffit plus en terme de performances.

Regard en arrière

Afin de pouvoir étudier les possibilités d’évolution, il est intéressant de se pencher sur l’offre que vous possédez actuellement, le serveur virtuel. En effet, le serveur virtuel est une machine virtuelle hébergée sur le même serveur physique de nombreuses autres en utilisant des technologies de virtualisation telles que VMWare ou Xen. L’inconvénient majeur de ce type de solution est, selon moi, la mutualisation des ressources de disque dur.

Les disques dur à plateau sont aujourd’hui le composant informatique qui a évolué le plus lentement en terme de performances. Ceci s’explique assez simplement par des contraintes physiques extrêmement complexes liées aux composants mécaniques de très haute précision. Si en plus, vous vous retrouvez mutualisés sur un jeu de disques dur à plateau, ça commence à devenir vraiment léger en terme de performances. Évidemment, les technologies telles que le RAID10 permettent d’obtenir des performances accrues mais ça reste assez modeste par rapport ce que peuvent offrir des SSD.

Les offres de machines virtuelles hébergées sur des machines physiques dotées de SSD existent mais elles sont assez rares et souvent onéreuses.

En avant !

La première solution qui se présente à vous lorsque vous souhaitez disposer de plus de performances est la solution du serveur dédié. En effet, au lieu de partager des ressources avec vos voisins, vous allez pouvoir tout garder pour vous.

En terme de choix, vous allez avoir face à vous une offre pléthorique. Vous aurez le choix entre de très nombreux fournisseurs différents disposant de très nombreuses offres. En terme de prix, l’entrée de gamme des serveurs dédies est tout à fait abordable même pour un particulier. Si vous acceptez de mettre un budget légèrement supérieur à l’entrée de gamme, vous accéderez rapidement à une puissance de calcul tout à fait conséquente.

Le choix de l’hébergeur est à faire en fonction des critères de prix et des fonctionnalités qui vous sont proposées. Une bonne solution pour avoir des retours est d’interroger des amis qui ont eu l’occasion de louer un serveur dédié. Vous allez ainsi pouvoir avoir un retour d’expérience concret vous permettant de vous faire une idée.

Lors de cette phase, le choix du serveur se fera probablement en fonction du budget dont vous disposez. Je ne peux que vous recommander de vous pencher sur le choix d’un serveur disposant de SSD. En effet, vous allez héberger sur un même serveur toute votre architecture web ce qui va générer des IO aléatoires et concurrents importants. Or, il s’agit d’un point sur lesquels les SSD sont très significativement plus performants que les disques dur à plateau.

Au niveau du choix du système d’exploitation, je ne peux que vous recommander de choisir le système d’exploitation avec lequel vous êtes le plus à l’aise si votre objectif est d’avoir une architecture stable. Il y a tout de même une nuance à apporter à ceci. Le choix d’une distribution de type « rolling release » telle que Arch Linux ou Gentoo bien qu’agréable à utiliser car disposant de versions très récentes des applications vous rajoutera un travail d’administration conséquent. En effet, le suivi des mises à jour de sécurité et des applications a besoin d’être très régulier. De plus, contrairement à des distributions telles que Debian ou CentOS, les versions de logiciels disponibles dans les dépôts ont fait l’objet d’une procédure de test moins approfondie. Pour résumer, c’est donc à vous de voir en fonction des vos objectifs et des vos sensibilités. Il n’y a pas vraiment de bon ou de mauvais choix, tout dépend de ce que vous souhaitez réaliser.

Les spécificités

Au niveau du système d’exploitation, il y aura peu de différences entre un serveur virtuel et un serveur dédié. Toute votre pile applicative sera hébergée dans un même système d’exploitation.

Les quelques différences se situent au niveau de l’interface avec le matériel physique. Tout d’abord, vous allez devoir gérer le RAID logiciel qui sera probablement fourni avec votre serveur. La mise en place du RAID sera probablement faite par défaut par votre hébergeur ou par vous-même à travers l’interface de gestion. Je ne peux que vous recommander de vous interroger sur le schéma de partitionnement avec lequel votre serveur sera livré car il correspondra peut être pas à ce que vous souhaitez. Il serait dommage de s’en rendre compte une fois que vous aurez tout installé.

La fonctionnalité la plus intéressante à activer au niveau de mdadm est l’activation des alertes par email en cas de défaillance du RAID. Il s’agit réellement d’une fonctionnalité indispensable car découvrir que votre RAID est mort lorsque vous commencez à avoir des erreurs de disque ou des kernel panic n’est pas très agréable. Vous disposez également d’un autre outil qui vous permettra de suivre la santé de vos disques. Il s’agit de SMART. Vous avez à votre disposition sous Linux le paquet « smartmontools » qui vous permettra d’exécuter des tests manuels mais aussi de mettre en place des tests réguliers avec envoi d’alertes email si jamais les choses ne se passent pas comme elles le devraient.

Bilan

Le passage du serveur virtuel vers le serveur dédié est le premier grand pas. En effet, vous êtes désormais libres de faire ce que vous souhaitez avec le matériel mis à disposition. Vous devrez rapidement remarquer une amélioration des performances de votre site ainsi qu’une capacité d’accueil de visiteurs assoiffés de contenu accrue.

Néanmoins, votre serveur dédié reste un SPOF conséquent car vous ne disposez que de très peu de redondance dans un serveur dédié. De plus, la cohabitation entre tous les composants de votre architecture dans un même système d’exploitation peut se passer plus ou moins bien. Dans le prochain article, nous allons donc nous intéresser à la prochaine étape de l’évolution de votre architecture, le passage vers plusieurs serveurs.

Les architectures web – Introduction

icone-projet-webC’est avec une émotion non dissimulée que je reprends ce blog que j’avais laissé à l’abandon depuis si longtemps. En effet, depuis de nombreuses choses se sont passées et j’en reviens ici. Je souhaite reprendre l’esprit initial de ce blog qui est de partager des informations sur l’Internet afin de pouvoir aider d’autres personnes qui se retrouveront dans des situations dans lesquelles je me suis trouvé plus tôt.

Cet article est l’introduction d’une série de billets que je compte écrire sur les architectures web appliquées aux logiciels Open Source. L’idée est de détailler les architectures permettant l’hébergement de sites Internet allant du site statique basique à un site complexe.

Les composants

Tout d’abord, il est utile de s’intéresser aux composants qui peuvent constituer une architecture web. Nous les classerons en trois catégories : les composants élémentaires, les composants de service et les composants de support.

Les composants élémentaires sont les composants que l’on retrouve dans toutes les architectures web classiques. Il s’agit du code du site qu’il s’agisse de code statique tel que du HTML ou du Javascript ou bien de code dynamique tel que du PHP, du Ruby on Rails voire même du C. Il s’agit également du jeu de données sur lequel le site se reposera afin d’afficher des données utiles à l’utilisateur. On y retrouvera ici des bases de données relationnelles ou non et les données brutes telles que des images ou des vidéos.

Les composants de service sont les composants que l’utilisateur va utiliser sans nécessairement en avoir conscience. Il s’agit des composants applicatifs chargés de générer les pages à partir du code du site, des composants de bases de données chargés de traiter les données ou bien des composants chargés de diriger l’utilisateur vers le serveur le plus approprié. Des exemples de logiciels Open Source servant de composants de service sont, par exemple, Phusion Passenger, Python, MySQL, MongoDB, nginx ou encore HAProxy.

Les composants de support sont les composants que l’utilisateur ne sera probablement jamais amené à interroger directement. Il s’agit des composants servant à assurer le bon fonctionnement et l’administration de l’architecture. On peut inclure dans cette catégorie les logiciels de gestion de configuration, les applications de supervision ainsi que les applications de déploiement de code. Des logiciels Open Source correspond à cette catégorie sont, par exemple, Puppet, chef, Nagios, Cacti, Zenoss, Webistrano ou git.

Le début

Dans cette série d’articles, nous ne nous intéresserons pas au cas de l’hébergement mutualisé. En effet, il s’agit probablement de la forme la plus simple d’hébergement du point de vue de l’utilisateur mais il s’agit en réalité d’une architecture web extrêmement complexe dont les complexités ne sont que cachées à l’utilisateur. Il est évident que la complexité d’une architecture mutualisée est différente en fonction de la taille de l’hébergeur mais néanmoins nous exclurons ce sujet de cette série d’articles.

Nous supposerons donc le cas le plus basique qui est celui d’un site web développé dans un langage de programmation tel que Ruby hébergé sur un serveur virtuel comme ceux que l’on peut trouver chez des hébergeurs tels que Gandi ou OVH pour ne citer que les plus gros. Ce site web reçoit une quantité de visite tout à fait raisonnable de l’ordre de 100 à 1000 visiteurs par jour.

Un serveur virtuel sera une solution idéale pour ce type de site car il permet la mise en place d’une pile applicative paramétrée en fonction des souhaits du développeur ou de l’administrateur système. Ainsi, toute la pile applicative sera retrouvera confinée à un système d’exploitation. Étant donné la nature d’un tel site et la probable non-criticité du service rendu, nous supposerons que les composants support sont réduits à un minimum.

La pile applicative

Dans le cas de notre site développé en Ruby, il y a plusieurs possibilités quant à la pile applicative. La solution la plus simple est d’utiliser WebRick le serveur HTTP inclus par défaut avec le framework Rails. De nombreux framework proposent un serveur web simpliste dont l’exécution se résume au lancement d’une simple commande. Cette solution permet de tester un site simplement mais est souvent limitée du fait de leur nature mono-threadés. Bien qu’un temps significatif soit gagné dans l’installation, il y a peu de chance que les performances soient au rendez-vous dès la moindre mise à l’épreuve.

C’est donc aussi rapidement qu’on se retrouve confronté au concept de « scalabilité », anglicisme issu du mot « scalability » qui décrit la capacité d’une architecture à grossir en fonction de la charge imposée. Ce sera le concept qui sera le fil conducteur de cette série d’articles.

Une fois la solution la plus simpliste éliminée, il nous reste donc à étudier l’utiliser de composants plus performants. Nous allons rapidement nous retrouver face à Apache, le serveur HTTP historique, et nginx, le serveur HTTP qui se veut rapide et flexible. Apache est probablement le logiciel Open Source pour lequel il est le plus simple de trouver des tutoriels en très grande quantité sur Internet. Il me parait même raisonnable de penser que si vous ne trouvez un article ou un tutoriel sur une fonctionnalité que vous souhaitez implémenter, c’est que c’est probablement impossible. Apache est capable d’exécuter un panel d’interpréteurs extrêmement large ainsi que des exécutables binaires via les interfaces CGI. De l’autre coté, nginx est une application dont le succès est beaucoup plus récent. La documentation est moins pléthorique qu’Apache mais elle est néanmoins assez simple à trouver.

Le choix du serveur HTTP est, selon moi, à faire en fonction de ses propres compétences à ce stade là. Si vous maitrisez l’un, vous aurez tout à fait raison de l’utiliser afin de simplifier votre architecture et rester sur des bases connues. Dans le cas de Ruby on Rails, l’installation de nginx avec le module Phusion Passenger se fait via une compilation automatisée par un script fourni. A contrario, l’installation d’Apache2 se fait via les modules présents dans n’importe quel distribution ce qui facilite grandement la tache.

Quant à l’application de gestion des données, vous aurez le choix entre MySQL et PostreSQL voire sqlite. Je n’entrerais pas dans le débat MySQL vs PostgreSQL néanmoins, comme pour le serveur HTTP, je ne peux que vous conseiller d’utiliser celui que vous maitrisez le mieux si l’objectif est de fiabiliser l’architecture. Quant à sqlite, son utilisation est en effet très simple néanmoins vous risquez de vous retrouver très rapidement limités par les fonctionnalités disponibles et les possibilités de scalabilité.

Bilan

Une telle architecture est particulièrement efficace en terme de coûts car elle ne nécessite qu’une seule VM dont le coût est relativement limité. De plus, en comparaison avec de l’hébergement mutualisé, vous aurez une liberté de manœuvre beaucoup plus grande.

L’inconvénient majeur de cette architecture simple est que vous ne disposez d’aucune redondance. Tous les composants sont des « SPOF » (Single Point of Failure ou, en Français, Point individuel de défaillance) ce qui signifie que la défaillance d’un seul de vos composants applicatifs entraine l’indisponibilité du site entier. De plus, le potentiel de performance d’une telle machine virtuelle à bas coût est relativement faible. Dès lors que le site commencera à atteindre une audience plus large et/ou plus régulière, vous allez devoir rapidement songer à passer à l’étape suivante.

Dans le prochain article, nous allons donc nous intéresser à la première étape permettant de faire grossir cette architecture afin qu’elle puisse accueillir plus de visiteurs.