Yann "Bug" Dubois

Développeur WordPress freelance à Paris
Flux RSS

Optimiser la configuration d’Apache

20 May 2011 Par : Yann Dubois Catégorie : Français, tech

L’optimisation d’Apache 2 est un vaste sujet, et je n’ai pas la prétention ici de le couvrir dans son intégralité. On peut optimiser Apache de différente façons, en jouant sur le modules chargés dynamiquement ou précompilés, en optimisant le système sous-jacent, ou tout simplement en changeant quelques paramètres dans ses fichiers de configuration. C’est uniquement sur ce dernier aspect que je m’attarde ici.

Le fichier apache2.conf / httpd.conf

Le fichier principal de configuration d’Apache 2 est /etc/apache2/apache2.conf

installé par défaut avec un paquet Debian, ou apache2/conf/httpd.conf pour les installations compilées à partir des sources Apache. Il comporte les paramètres suivants auxquels nous allons nous intéresser (listés dans l’ordre où ils apparaissent dans le fichier de configuration par défaut) :

Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxClients          150
    MaxRequestsPerChild   0
</IfModule>
HostnameLookups Off
LogLevel warn

Savoir quels modules sont compilés

sudo apache2 -l

-> détermine le module MPM utilisé (par défaut sous Debian 6 : prefork.c)
En résumé, sous Debian, le choix de module MPM se résume à deux possibilités : le module Prefork ou le module Worker. Le module prefork étant compilé par défaut dans le paquet Debian, et comme nous avons dit que nous ne nous intéressions pas aux optimisations nécessitant recompilation dans cet article, nous nous concentrerons sur les réglages du module MPM Prefork, qui est de toute façon recommandé par Apache dans la plupart des cas pour sa robustesse.

Les réglages

  • Timeout : réglé par défaut à 300 (c’est à dire 5 minutes), ce seuil peut éventuellement être abaissé si vous rencontrez de gros problèmes de performances dus à des connexions très lentes qui encombrent votre serveur. En pratique, il n’y a pas de gain de performance à le modifier.
  • KeepAlive On : il est recommandé d’utiliser cette fonctionnalité de la norme http1.1 qui permet de réutiliser une connexion ouverte pour envoyer plusieurs documents au même client. C’est notamment très utile pour permettre au navigateur de télécharger les images contenues dans une page en économisant l’ouverture de connexions successives. Il faut cependant faire attention aux réglages de MaxKeepAliveRequests et KeepAliveTimeout (ci-dessous) qui y sont liés, car dans certains cas, la fonctionnalité keepalive peut ralentir les performances d’un serveur web (avec des trafics lents, trop importants, ou en cas d’attaques délibérées). Dans des cas critiques (serveur qui s’effondre faute de mémoire) il peut être intéressant de suspendre momentanément cette fonctionnalité, le temps de rétablir la situation… Dans d’autres cas, cela ne fera qu’empirer les choses !
  • MaxKeepAliveRequests : réglé par défaut à 100, vous pouvez abaisser ce seuil si vous avez besoin de faire “mourir” plus rapidement vos processus à la suite de fuites de mémoire, mais dans la plupart des cas vous n’avez pas intérêt à l’abaisser. Vous pouvez même l’augmenter un peu si vos pages contiennent beaucoup d’images, ou si vos utilisateurs font beaucoup de pages vues par visites, ou si vous procédez à des rechargements automatiques ou à des opérations se succédant rapidement en Ajax, etc. Vous ne risquez pas grand chose à l’augmenter à 150 par exemple.
  • KeepAliveTimeout : réglé par défaut à 15 secondes, c’est en général beaucoup trop. Si vous n’avez pas de raison spécifique de vouloir maintenir artificiellement des connexions ouvertes avec vos clients pendant aussi longtemps, baissez ce seuil à 2 secondes. Si vous rencontrez des gros problèmes de charges, baissez-le provisoirement à 1 seconde.
  • StartServers : réglé par défaut à 5, ce paramètre ne joue en pratique que lors des redémarrages du serveur web. Il n’a donc pas une grande importance. Vous pouvez l’augmenter si vous savez que votre serveur peut faire face à tout moment à des brusques pics d’audience, afin qu’il soit prêt à les affronter après un redémarrage. Il indique le nombre d’instances Apache simultané à lancer dès le redémarrage. Sachant qu’Apache s’occupera de lancer des instances supplémentaires s’il en faut plus.
  • MinSpareServers : indique le nombre de processus Apache qu’il faut garder disponible à tout moment pour faire face aux variations de fréquentation, la limite étant de toute façon MaxSpareServers. Réglé par défaut à 5.
  • MaxSpareServers : indique le nombre maximum de processus Apache inutilisés qu’on peut laisser en attente. Réglé par défaut à 10. Si vous rencontrez des problèmes de fuite mémoire, vous avez vraissemblablement intérêt à ne pas augmenter ce chiffre. Mais attention : si vous l’abaissez trop, votre serveur va passer son temps à “tuer” et à “recréer” des processus, ce qui va sensiblement augmenter la charge CPU et la charge serveur globale. Il faut donc toujours se ménager une marge de sécurité. Si vous n’avez pas de problème de mémoire, vous pouvez sensiblement augmenter ce nombre afin d’éviter de détruire des processus “pour le plaisir”, et de garder en permanence un maximum de serveurs prêts à répondre aux fluctuations de fréquentation.
  • MaxClients : C’est le paramètre le plus important dans la configuration Apache ! En théorie, vous devez régler ce nombre en fonction de la mémoire moyenne utilisée par un de vos processus Apache et de la mémoire totale disponible pour Apache sur votre système. Malheureusement ce n’est pas toujours possible quand on travaille avec mod-php : comme expliqué à la fin de cet autre article sur l’optimisation d’Apache en tandem avec NginX, la réutilisation des processus a tendance à faire “gonfler” énormément la consommation mémoire des instances Apache, qui ne “rendent” la mémoire que quand elles s’éteignent. En pratique, les instances Apache ont donc tendance à consommer systématiquement la mémoire nécessaire à l’exécution de votre plus “gros” script PHP à tout moment.
    Voilà comment vos instances Apache/mod-php en viendront vite à consommer plusieurs centaines de mégaoctets chacune : si votre serveur n’a qu’un ou 2 Go de mémoire, vous devrez en théorie abaisser de façon draconienne ce paramètre MaxClients, qui est réglé par défaut à 150. Plus vos applications PHP sont “lourdes” (par exemple un CMS évolué comme WordPress ou un framework), plus vous allez devoir théoriquement réduire le nombre de clients acceptés en parallèle pour éviter la saturation mémoire, qui provoquerait immédiatement le swap sur disque et l’effondrement du serveur. En pratique les choses ne sont pas si simples : on peut “jongler” avec le nombre de clients acceptables, à condition de s’assurer que la mémoire absorbée par les processus Apache est régulièrement “purgée”. Pour cela, il faut réduire la réutilisation des processus, car en les obligeant à “mourir” plus souvent, on évite la fuite en avant permanente dans l’usage de la mémoire.
    Dans les cas critiques, afin de ne pas trop diminuer le nombre total de “slots” Apache disponibles pour accueillir les connexions, on peut être amené à entraver la réutilisation des processus (en abaissant le paramètre MaxRequestsPerChild abordé ci-dessous), ce qui va augmenter la charge CPU mais libérer beaucoup plus vite la mémoire. Si vos applications PHP sont “atypiques” ou asymétriques (avec quelques “gros scripts” PHP qui nécessitent beaucoup de mémoire mélangés à des traitements moins gourmands), cette solution peut vous sauver la mise. Il faudra à moyen terme envisager de dédier un serveur web à vos différents types de traitements (voir par exemple comment coupler Apache à NginX pour éviter d’utiliser Apache pour servir les fichiers statiques). En résumé : si vous avez des problèmes de saturation mémoire, il faut réduire considérablement le paramètre MaxClients, puis jouer sur le paramètre MaxRequestsPerChild pour voir jusqu’où vous arrivez à le remonter sans causer l’emballement de votre serveur… C’est un problème de gestion de risque…
  • MaxRequestsPerChild : c’est l’autre paramètre fondamental si vous rencontrez des problèmes de mémoire. Si vous n’avez pas de problème d’utilisation de la mémoire par Apache, vous pouvez le laisser à son réglage par défaut (0), ce qui signifie que les processus n’expirent jamais ! Dès que vous rencontrez des problèmes de mémoire, même occasionnels, il faut régler ce paramètre différemment pour éviter les “fuites”. Si vous êtes à un stade critique, abaissez ce chiffre de façon draconienne (par exemple 10, voire moins). Une fois que votre serveur sera stabilisé en jouant sur d’autres paramètres (optimisation du code PHP, utilisation d’un cache d’opcode, répartition des statiques sur un autre serveur,…), vous pourrez remonter significativement ce chiffre (par exemple 1500), mais en évitant de le laisser à zéro pour être sur que sur le long terme il y ait un minimum de “rotation” dans l’usage de la mémoire : cela peut jouer énormément pour pérenniser la fiabilité de votre serveur web. Mieux vaut forcer les instances à redémarrer de temps en temps (c’est quasiment indolore sur des systèmes modernes), plutôt que de devoir redémarrer tout votre serveur une fois par mois après un crash suite à la saturation de la mémoire !
  • HostnameLookups : sur un serveur chargé et que vous devez optimiser, laissez ce paramètre à Off. Si vous voulez vraiment résoudre les adresses IP de tous vos visiteurs, faites-le de façon asynchrone, sur un serveur de statistiques séparé de votre serveur de production.
  • LogLevel warn : sur un serveur de production très chargé sur lequel de nombreux fichiers manquants viendraient par exemple à provoquer un volume très important d’erreurs, vous pourriez gagner à baisser le seuil de sensibilité du journal d’erreurs. Evitez de le désactiver complètement cependant, au risque de ne plus avoir aucune trace de ce qui ne tourne pas rond sur votre machine.

En résumé

Si vous avez des problèmes de mémoire RAM : baissez le MaxClients, le MaxKeepAliveRequests, le KeepAliveTimeout, le MaxSpareServers et un indiquez un nombre relativement faible pour MaxRequestsPerChild : cela va faire baisser l’utilisation moyenne de la mémoire en forçant les processus à mourir plus souvent, en libérant leur mémoire. Mais cela va abaisser les performances globales et augmenter la charge CPU. Par rapport à un serveur qui sature sa mémoire et swappe sur le disque ou plante régulièrement, cela reste un moindre mal… au moins le temps de régler les problèmes à la source (optimisation du code PHP,…) Par ailleurs, vous pouvez avoir intérêt à réduire les performances de votre serveur web pour réserver de la mémoire à vos caches de base de données (si elles sont sur la même machine) ou d’opcode : au final, vous serez souvent gagnants si vos ressources sont limitées. Redémarrer un processus Apache “coûte” bien moins cher à votre système que de devoir recompiler à la volée un script PHP ou une requête MySql qui auraient pu être en mémoire…

Si vous voulez augmenter les performances et que vous n’avez pas de problème de mémoire : la configuration par défaut d’Apache est en général performante. Vous pourrez peut-être gagner à la marge (si la mémoire et les performances de votre système le permettent) en augmentant le MaxClients ou le MaxSpareServers sur des systèmes qui doivent accepter de très nombreuses connexions simultanées. Sur la plupart des autres systèmes, les gains de performances sont à chercher ailleurs : structure des pages web, optimisation du code PHP et des requêtes SQL, passage en asynchrone des appels externe, mises en cache, architecture sous-jacente. Vous pouvez aussi expérimenter le MPM Worker, ce qui nécessitera une re-compilation d’Apache.

Exemple de configuration sur un serveur dédié OVH avec 24 Go de RAM et de forts pics de trafic (WordPress / NginX / Apache / eAccelerator)

Timeout 300
KeepAlive On
MaxKeepAliveRequests 2048
KeepAliveTimeout 6
HostnameLookups Off
<IfModule mpm_prefork_module>
 StartServers          64
 MinSpareServers       128
 MaxSpareServers       256
 ServerLimit           512
 MaxClients            512
 MaxRequestsPerChild   65536
</IfModule>

…n’allez pas essayer ce genre de configuration sur un serveur ne disposant pas d’énormes quantités de RAM !
NB: Le paramètre ServerLimit devient nécessaire quand on veut dépasser la barrière de 256 processus autorisée par défaut dans Apache.

Liens utiles

A lire également...

WordPress › Error

There has been a critical error on your website.

Learn more about debugging in WordPress.