Le Rayon UX

La radiographie du Web en temps presque réel / thème en chantier (je m'appelle Teuse)

Le tuning Apache pour augmenter les performances de votre application web

Les problèmes de montée en charge sont choses courantes pour un site ou une application web une fois atteint un certain succès. Ces derniers sont bien trop souvent négligés, généralement jusqu’au jour où se trouve atteinte la limite critique entre l’inconfort et l’instabilité. Le trend actuel veut qu’il soit à la fois plus simple et moins cher de rajouter des machines que de reprendre son code en profondeur pour l’optimiser. Encore faut-il que l’application permette un redimensionnement de ce genre sans rentrer dans une phase de refactoring complet. Évidemment, avant d’en arriver à une solution aussi lourde, il vaut mieux s’assurer que tout a été fait pour exploiter au mieux les ressources disponibles, et cela passe notamment par un peu d’optimisation côté serveur.

Les quelques conseils distillés dans cet article ne s’appliquent pas à n’importe quel type de site web, ne les prenez donc pas pour parole d’évangile avant de vous assurer que vous rentriez bien dans la cible visée. Ils visent à améliorer les points suivants :

  • Côté applicatif, limiter au maximum les calculs faisant intervenir le processeur et les accès disques, en évitant au maximum les modifications.
  • Limiter les accès disques pour les contenus statiques à servir.
  • Économiser un peu de bande passante quand cela n’implique pas de mettre le processeur à genoux.

Cet article fonctionne exactement comme le rapport Attali : si vous en retirez un seul point, ou que vous retirez celui-ci de son contexte, vous risquez non seulement de ne pas atteindre le but espéré, mais également de vous retrouver avec le contraire de ce à quoi vous vous attendiez.

Rendez votre contenu statique

Si votre application vous le permet, rendez un maximum de contenu statique, le mieux étant de créer de simples pages HTML qui seront appelées par défaut si elles existent et générées dans le cas contraire. La majorité des CMS et des blogware le font, pour les autres, vous pouvez utiliser caches_page en Ruby on Rails, ou Skycache en PHP. L’intérêt d’une telle démarche est évidente : la présence de tels fichiers statiques sur le disque évite toute requête à votre application, Apache servant directement le contenus.

Concaténez vos fichiers CSS, Javascript et vos images CSS

Afin d’économiser les requêtes HTTP, concaténez vos fichiers CSS et vos fichiers Javascript entre eux. Cela n’est cependant pas toujours possible. Il n’est par exemple pas possible d’assembler Prototype et Scriptaculous. Outre l’économie de requêtes HTTP sur des fichiers de très petite taille, cela nous sera utile un peu plus tard.

Assemblez également vos images CSS, particulièrement les pictogrammes et les modifications onmouseover / onmouseout. Au lieu de remplacer l’image de fond, il vous suffit alors de la positionner avec background-position. Vous faites ici des économies non seulement de requêtes, mais également d’accès disques.

Mettez vos sessions en cache avec memcached

Memcached est un système de cache très générique dans lequel les objets sont placés en mémoire. Il a été créé afin d’optimiser les applications web en allégeant la charge des bases de données. Cette partie s’adresse aux utilisateurs de Ruby on Rails. J’imagine que la manipulation est également possible en PHP, mais j’avoue ne pas m’y être penché pour l’instant, même si ça risque d’arriver sous peu.

Il existe trois manières de socker les sessions coté serveur :

  1. Sur le système de fichiers, par exemple dans /tmp.
  2. Dans la base de données.
  3. En Ram, grâce à memcache.

Dans un premier temps, installez memcached sur votre système.

    # aptitude install memcached
    # /etc/init.d/memcached start

Puis, installez la gem memcache-client, ou mieux, incluez-la dans votre application si vous comptez la redistribuer :

    # gem install memcache-client

Enfin, éditez votre fichier config/environment.rb afin d’y ajouter les lignes suivantes :

require 'memcache-client'
config.action_controller.session_store = :mem_cache_store

Redémarrez vos processus CGI, vous y êtes. Vous venez d’économiser un nombre conséquent d’accès disques ou de requêtes sur votre base de données. Bravo !

Mettez les éléments en cache avec mod_expires

Mod_expires est un module Apache bien pratique qui ajoute une date d’expiration dans les en-têtes HTTP de vos fichiers. Il est à utiliser sans modération sur les fichiers qui ne changent pas, ou très peu. Vous l’appliquerez donc à vos images, qu’elles soient dans le contenu ou CSS, à vos feuilles de style, vos fichiers javascript, et éventuellement vos PDF.

Activer mod_expires est très simple :

    # a2enmod expires

Ajoutez ensuite les lignes suivantes soit dans le fichier expires.conf si vous souhaitez l’activer sur l’ensemble du site, soit dans le fichier de description de votre vhost si vous ne souhaitez l’appliquer que sur un site :

<IfModule mod_expires.c>
  <FilesMatch "\.(jpg|gif|png|pdf|css|js)$">
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
  </FilesMatch>
</IfModule>    

Nous avons activé le cache sur les fichiers pour une durée d’un mois, mais n’hésitez pas à le rendre plus court si vous craignez de faire des modifications de temps en temps. Une solution pour autoriser les modifications est d’accoler le timestamp de sa dernière modification au nom du fichier.

Compresser avec mod_deflate

Moddeflate, ou modgzip sur Apache 1.3 compresse les fichiers avant de les envoyer au navigateur pourvu que celui-ci accepte ce mode de transfert. Nous allons l’utiliser pour réduire la taille des fichiers texte envoyés par le serveur : CSS, Javascript, HTML ou XML. Le format texte se compresse en effet très bien, le fichier final faisant jusqu’à 15% de l’original, avec une consommation très faible du processeur.

Comme précédemment, activez le module Apache :

    # a2enmod deflate

Ou si vous utilisez Apache 1.3 :

    # a2enmod gzip
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css text/js application/x-javascript text/plain text/xml
</IfModule>

Désactivez les ETags

Les ETags, pour Entity Tags, sont des informations contenues dans les en-têtes HTTP permettent de savoir si un contenu a été modifié sur le serveur depuis son dernier chargement. Si l’etag sur côté serveur est le même que coté client, alors le serveur renvoie un code de retour 304. Dans le cas contraire, Apache sert le fichier. L’utilisation d’ETag peut s’avérer problématique, notamment dans lorsque la charge est répartie sur plusieurs serveurs. L’ETag est en effet généré à partir d’informations prises sur le système de fichier, et celles-ci changeront d’un serveur à l’autre, rendant l’utilité de l’ETag caduque.

Dans notre configuration actuelle, nous avons tout intérêt à désactiver les etags. En effet, les fichiers sont stockés en cache côté client pendant un mois, ce dernier n’effectuera donc pas la demande de fichier, et pour les autres, on évitera les aller retours à grands coups de 304.

FileETag none

Enfin, redémarrez Apache après en avoir validé la configuration :

    # apache2ctl -t
    # /etc/init.d/apache2 restart

Et voilà, c’est fait. Vous venez d’augmenter très sensiblement les performances de votre application web sans en modifier le code en profondeur. Dans un prochain article, nous verrons comment optimiser encore vos applications en utilisant intelligemment memcached pour stocker le résultat de vos requêtes SQL.

Notre dame vue du pont de la tournelle

  • Par Rik 17/02/2008 at 19h22

    Plutôt que de désactiver les Etag, il peut être approprié de les configurer pour ne pas tenir compte de l’inode. La config par défaut d’Apache est FileETag INode MTime Size, un truc comme FileETag MTime Size ou juste FileETag Size peut-être intéressant.

    Jouer avec KeepAlive peut-être intéressant. Lors des grosses charges, il vaut mieux le désactiver en règle générale. Cela permet de mieux répartir la demande de slots. Un utilisateur avec une connexion lente ne mobilisera pas un slot trop longtemps.


  • Par Jean-Sébastien Mansart 17/02/2008 at 22h22

    Dans le même genre, mais sur une autre plateforme, j’ai écris un billet sur comment optimiser un site Plone : http://www.jsmansart.com/post/Optimisation-dun-site-Plone

    Je pense qu’il y a des parties de ton articles qui peuvent être largement appliquées à l’optimisation d’un site Plone.


  • Par Bob 18/02/2008 at 11h10

    Le fait de compresser les entêtes prendra surement moins de bande passante et accélèrera le chargement de l’application coté client mais cela prendra des ressources coté serveur donc c’est une fonction à utiliser avec précautions…


  • Par geb 18/02/2008 at 15h51

    vraiment intéréssant cet article.

    Plusieurs remarques:

    L’utilisation d’un proxy http (via un module d’apache) permet de mettre des pages en cache sans retoucher au code, parfois (poids de l’existent toutca) ça peut être sacrément utile.

    J’éssai aussi de garder un cache de mes objets métiés (base de données), en serialisant ceux ci. Cela peut être utile quand on ne peut pas avoir des html statiques facilemen (ou pas pour toutes les pages)t.

    Pour l’utilisation de memcache , adodb (adodb.sf.net) contient plein de bonnes choses dont une integration assez basique mais qui fait ce qu’on lui demande.

    Enfin, l’utilisation de cache php (APC , zend optimizer etc) peut être intéréssant mais je n’ai pas eu trop le temps de creuser (et ils peuvent poser problemes avec certains codes)


  • Par Nath 18/02/2008 at 16h28

    Pour la mise en cache des fichiers statiques coté client (et bénéficier aussi des proxy), certains préconisent même une durée de vie illimitée (genre 10 ans). Et si on modifie le fichier, on change son nom pour forcer son re-chargement.

    Ça peut devenir très fastidieux, mais une méthode très ingénieuse permet de le faire automatiquement : http://particletree.com/notebook/automatically-version-your-css-and-javascript-files/


  • Par Frédéric de Villamil 18/02/2008 at 18h44

    @Rik : suite à notre discussion, j’ai joué un peu avec KeepAlive, et je ne suis pas super pour le virer, mais plutôt pour mettre un KeepAliveTimeout très très bas pour libérer les slots rapidement.

    @J-S : c’est pas très bien de faire sa pub comme ça sans que ça apporte quoi que ce soit au débat. Prochaine fois, je censure.

    @Bob : c’est exactement ce que j’ai dit.

    @Gebura : j’ai voulu faire un billet qui ne demande pas de modifier (trop) son archi et notamment de foutre un proxy, bien que dans un monde idéal c’est ce que j’utiliserais, avec un peu de load balancing. Le cache des objets métiers est le sujet dont je vais parler dans l’article à venir sur memcached + cache de model, et pour adodb, j’aime super moyen, mais il fait effectivement son boulot.

    @Nath : pas une bonne idée ça 10 ans, et sinon c’est exactement la méthode qu’on utilise pour typo.


Commentaire Le tuning Apache pour augmenter les performances de votre application web