Il est dit dans la documentation d'Apache 1.3 à propos de l'amélioration des performances :
"Apache est un serveur web à vocation générale, conçu pour être non seulement efficace mais aussi rapide. Dans sa configuration de base, ses performances sont déjà relativement satisfaisantes. La plupart des sites possèdent une bande passante en sortie inférieure à 10 Mbits que le serveur Apache peut mettre pleinement à profit en utilisant un serveur à base de processeur Pentium bas de gamme."
Cette phrase ayant été écrite il y a plusieurs années, entre temps de nombreuses choses ont changé. D'une part, les serveurs sont devenus beaucoup plus rapides. D'autre part, de nombreux sites se voient maintenant allouée une bande passante en sortie bien supérieure à 10 Mbits. En outre, les applications web sont devenues beaucoup plus complexes. Les sites classiques ne proposant que des pages du style brochure sont toujours présents, mais le web a souvent évolué vers une plateforme exécutant des traitements, et les webmasters peuvent maintenant mettre en ligne des contenus dynamiques en Perl, PHP ou Java, qui exigent un niveau de performances bien supérieur.
C'est pourquoi en dépit des progrès en matière de bandes passantes allouées et de rapidité des serveurs, les performances des serveurs web et des applications web sont toujours un sujet d'actualité. C'est dans ce cadre que cette documentation s'attache à présenter de nombreux points concernant les performances des serveurs web.
Ce document se concentre sur l'amélioration des performances via des options facilement accessibles, ainsi que sur les outils de monitoring. Les outils de monitoring vous permettront de surveiller le fonctionnement de votre serveur web afin de rassembler des informations à propos de ses performances et des éventuels problèmes qui s'y rapportent. Nous supposerons que votre budget n'est pas illimité ; c'est pourquoi les améliorations apportées le seront sans modifier l'infrastructure matérielle existante. Vous ne souhaitez probablement pas compiler vous-même votre serveur Apache, ni recompiler le noyau de votre système d'exploitation ; nous supposerons cependant que vous possédez quelques notions à propos du fichier de configuration du serveur HTTP Apache.
Si vous envisagez de redimensionner ou d'améliorer les performances de votre serveur, vous devez tout d'abord observer la manière dont il fonctionne. En observant son fonctionnement en conditions réelles ou sous une charge créée artificiellement, vous serez en mesure d'extrapoler son fonctionnement sous une charge accrue, par exemple dans le cas où il serait mentionné sur Slashdot.
L'outil top est fourni avec Linux et FreeBSD. Solaris
		quant à lui, fournit prstat(1). Cet outil
		permet de rassembler de nombreuses données statistiques
		à propos du système et de chaque processus en cours
		d'exécution avant de les afficher de manière
		interactive sur votre terminal. Les données affichées
		sont rafraîchies toutes les secondes et varient en
		fonction de la plateforme, mais elles comportent en
		général la charge moyenne du système, le nombre de
		processus et leur état courant, le pourcentage de temps
		CPU(s) passé à exécuter le code système et utilisateur,
		et l'état de la mémoire virtuelle système. Les données
		affichées pour chaque processus sont en général
		configurables et comprennent le nom et l'identifiant du
		processus, sa priorité et la valeur définie par nice,
		l'empreinte mémoire, et le pourcentage d'utilisation CPU.
		L'exemple suivant montre plusieurs processus httpd (avec
		les MPM worker et event) s'exécutant sur un système
		Linux (Xen) : 
                
top - 23:10:58 up 71 days,  6:14,  4 users,  load average: 0.25, 0.53, 0.47
Tasks: 163 total,   1 running, 162 sleeping,   0 stopped,   0 zombie
Cpu(s): 11.6%us,  0.7%sy,  0.0%ni, 87.3%id,  0.4%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   2621656k total,  2178684k used,   442972k free,   100500k buffers
Swap:  4194296k total,   860584k used,  3333712k free,  1157552k cached
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
16687 example_  20   0 1200m 547m 179m S   45 21.4   1:09.59 httpd-worker
15195 www       20   0  441m  33m 2468 S    0  1.3   0:41.41 httpd-worker
    1 root      20   0 10312  328  308 S    0  0.0   0:33.17 init
    2 root      15  -5     0    0    0 S    0  0.0   0:00.00 kthreadd
    3 root      RT  -5     0    0    0 S    0  0.0   0:00.14 migration/0
    4 root      15  -5     0    0    0 S    0  0.0   0:04.58 ksoftirqd/0
    5 root      RT  -5     0    0    0 S    0  0.0   4:45.89 watchdog/0
    6 root      15  -5     0    0    0 S    0  0.0   1:42.52 events/0
    7 root      15  -5     0    0    0 S    0  0.0   0:00.00 khelper
   19 root      15  -5     0    0    0 S    0  0.0   0:00.00 xenwatch
   20 root      15  -5     0    0    0 S    0  0.0   0:00.00 xenbus
   28 root      RT  -5     0    0    0 S    0  0.0   0:00.14 migration/1
   29 root      15  -5     0    0    0 S    0  0.0   0:00.20 ksoftirqd/1
   30 root      RT  -5     0    0    0 S    0  0.0   0:05.96 watchdog/1
   31 root      15  -5     0    0    0 S    0  0.0   1:18.35 events/1
   32 root      RT  -5     0    0    0 S    0  0.0   0:00.08 migration/2
   33 root      15  -5     0    0    0 S    0  0.0   0:00.18 ksoftirqd/2
   34 root      RT  -5     0    0    0 S    0  0.0   0:06.00 watchdog/2
   35 root      15  -5     0    0    0 S    0  0.0   1:08.39 events/2
   36 root      RT  -5     0    0    0 S    0  0.0   0:00.10 migration/3
   37 root      15  -5     0    0    0 S    0  0.0   0:00.16 ksoftirqd/3
   38 root      RT  -5     0    0    0 S    0  0.0   0:06.08 watchdog/3
   39 root      15  -5     0    0    0 S    0  0.0   1:22.81 events/3
   68 root      15  -5     0    0    0 S    0  0.0   0:06.28 kblockd/0
   69 root      15  -5     0    0    0 S    0  0.0   0:00.04 kblockd/1
   70 root      15  -5     0    0    0 S    0  0.0   0:00.04 kblockd/2Top est un merveilleux outil, même s'il est relativement gourmand en ressources (lorsqu'il s'exécute, son propre processus se trouve en général dans le top dix des consommations CPU). Il est indispensable pour déterminer la taille d'un processus en cours d'exécution, information précieuse lorsque vous voudrez déterminer combien de processus httpd vous pourrez exécuter sur votre machine. La méthode pour effectuer ce calcul est décrite ici : calculer MaxClients. Top est cependant un outil interactif, et l'exécuter de manière continu présente peu ou pas d'avantage.
Cette commande n'est disponible que sous Linux. Elle indique la mémoire vive et l'espace de swap utilisés. Linux alloue la mémoire inutilisée en tant que cache du système de fichiers. La commande free montre l'utilisation de la mémoire avec et sans ce cache. On peut utiliser la commande free pour déterminer la quantité de mémoire utilisée par le système, comme décrit dans le paragraphe calculer MaxClients. L'affichage de la sortie de la commande free ressemble à ceci :
sctemme@brutus:~$ free
              total       used     free   shared    buffers    cached
Mem:        4026028    3901892   124136         0    253144    841044
-/+ buffers/cache:     2807704  1218324
Swap:       3903784      12540  3891244
                Cette commande est disponible sur de nombreuses
		plateformes de style Unix. Elle affiche un grand nombre
		de données système. Lancée sans argument, elle affiche
		une ligne d'état pour l'instant actuel. Lorsqu'on lui
		ajoute un chiffre, la ligne d'état actuelle est ajoutée à
		intervalles réguliers à l'affichage existant.
		Par exemple, la commande
		vmstat 5 ajoute la ligne d'état actuelle
		toutes les 5 secondes. La commande vmstat affiche la
		quantité de mémoire virtuelle utilisée, la quantité de
		mémoire échangée avec l'espace de swap en entrée et en
		sortie à chaque seconde, le nombre de processus
		actuellement en cours d'exécution ou inactifs, le nombre
		d'interruptions et de changements de contexte par
		seconde, et le pourcentage d'utilisation du CPU. 
                
                    Voici la sortie de la commande vmstat
		    pour un serveur inactif : 
                
[sctemme@GayDeceiver sctemme]$ vmstat 5 3
   procs                      memory     swap         io    system        cpu
 r b w     swpd   free   buff cache si so       bi    bo in     cs us  sy id
 0 0 0        0 186252   6688 37516    0    0   12     5 47    311  0   1 99
 0 0 0        0 186244   6696 37516    0    0    0    16 41    314  0   0 100
 0 0 0        0 186236   6704 37516    0    0    0     9 44    314  0   0 100
                  Et voici cette même sortie pour un serveur en charge de cent connexions simultanées pour du contenu statique :
[sctemme@GayDeceiver sctemme]$ vmstat 5 3
   procs                      memory     swap    io      system       cpu
 r b w     swpd   free   buff cache si so     bi bo   in     cs us sy  id
 1 0 1        0 162580   6848 40056    0    0 11  5 150     324  1  1  98
 6 0 1        0 163280   6856 40248    0    0  0 66 6384 1117   42 25  32
11 0 0        0 162780   6864 40436    0    0  0 61 6309 1165   33 28  40
                  La première ligne indique des valeurs moyennes depuis le dernier redémarrage. Les lignes suivantes donnent des informations d'état à intervalles de 5 secondes. Le second argument demande à vmstat de générer 3 lignes d'état, puis de s'arrêter.
La boîte à outils SE est une solution de supervision pour Solaris. Son langage de programmation est basé sur le préprocesseur C et est fourni avec de nombreux exemples de scripts. Les informations fournies peuvent être exploitées en mode console ou en mode graphique. Cette boîte à outils peut aussi être programmée pour appliquer des règles aux données système. Avec l'exemple de script de la Figure 2, Zoom.se, des voyants verts, oranges ou rouges s'allument lorsque certaines valeurs du système dépassent un seuil spécifié. Un autre script fourni, Virtual Adrian, permet d'affiner les performances en tenant compte de ces valeurs.
Depuis sa création, de nombreux propriétaires se sont succédés à la tête de la boîte à outils SE, et elle a de ce fait largement évolué. Il semble qu'elle ait maintenant trouvé sa place chez Sunfreeware.com d'où elle peut être téléchargée gratuitement. Il n'y a qu'un seul paquet pour Solaris 8, 9 et 10 sur SPARC et x86, et il inclut le code source. Le concepteur de la boîte à outils SE, Richard Pettit, a fondé une nouvelle sociéte, Captive Metrics4, et a l'intention de mettre sur le marché un outil de supervision multiplateforme en Java basé sur les mêmes principes que la boîte à outils SE.
Etant donné que DTrace est disponible sous Solaris, FreeBSD et OS X, il serait intéressant de l'étudier. Il y a aussi le module mod_dtrace pour httpd.
Le module mod_status donne un aperçu des performances
		du serveur à un instant donné. Il génère une page HTML
		comportant, entre autres, le nombre de processus Apache
		en cours d'exécution avec la quantité de données qu'ils
		ont servies, ainsi que la charge CPU induite par httpd
		et le reste du système. L'Apache Software Foundation
		utilise elle-même ExtendedStatus On à votre fichier
		httpd.conf, la page de
		
Le moyen le plus efficace pour vérifier la bonne santé et le niveau de performance de votre serveur consiste à surveiller et analyser les journaux écrits par httpd. La surveillance du journal des erreurs vous permet de déterminer les sources d'erreurs, de détecter des attaques ou des problèmes de performance. L'analyse du journal des accès vous indique le niveau de charge de votre serveur, quelles sont les ressources les plus populaires, ainsi que la provenance de vos utilisateurs. Une analyse historique des données de journalisation peut vous fournir des informations précieuses quant aux tendances d'utilisation de votre serveur au cours du temps, ce qui vous permet de prévoir les périodes où les besoins en performance risquent de dépasser les capacités du serveur.
Le journal des erreurs peut indiquer que le nombre maximum de processus actifs ou de fichiers ouverts simultanément a été atteint. Le journal des erreurs signele aussi le lancement de processus supplémentaires selon un taux supérieur à la normale en réponse à une augmentation soudaine de la charge. Lorsque le serveur démarre, le descripteur de fichier stderr est redirigé vers le journal des erreurs, si bien que toute erreur rencontrée par httpd après avoir ouvert ses fichiers journaux apparaîtra dans ce journal. Consulter fréquemment le journal des erreurs est donc une bonne habitude.
Lorsque Apache httpd n'a pas encore ouvert ses
		fichiers journaux, tout message d'erreur sera envoyé
		vers la sortie d'erreur standard stderr. Si vous
		démarrez httpd manuellement, ces messages d'erreur
		apparaîtront sur votre terminal, et vous pourrez les
		utiliser directement pour résoudre les problèmes de
		votre serveur. Si httpd est lancé via un script de
		démarrage, la destination de ces messages d'erreur
		dépend de leur conception.
		/var/log/messages est alors le premier fichier à
		consulter. Sous Windows, ces messages d'erreur précoces
		sont écrits dans le journal des évènements des
		applications, qui peut être visualisé via l'observateur
		d'évènements dans les outils d'administration. 
                
                    Le journal des erreurs est configuré via les
		    directives de configuration 
Dans le cas d'un serveur accessible depuis Internet, attendez-vous à voir de nombreuses tentatives d'exploitation et attaques de vers dans le journal des erreurs. La plupart d'entre elles ciblent des serveurs autres qu'Apache, mais dans l'état actuel des choses, les scripts se contentent d'envoyer leurs attaques vers tout port ouvert, sans tenir compte du serveur web effectivement en cours d'exécution ou du type des applications installées. Vous pouvez bloquer ces tentatives d'attaque en utilisant un pare-feu ou le module mod_security, mais ceci dépasse la portée de cette discussion.
                    La directive 
| 
                             Niveau  | 
                        
                             Description  | 
                    
| 
                             emerg  | 
                        
                             Urgence - le système est inutilisable.  | 
                    
| 
                             alert  | 
                        
                             Une action doit être entreprise immédiatement.  | 
                    
| 
                             crit  | 
                        
                             Situations critiques.  | 
                    
| 
                             error  | 
                        
                             Situations d'erreur.  | 
                    
| 
                             warn  | 
                        
                             Situations provoquant un avertissement.  | 
                    
| 
                             notice  | 
                        
                             Evènement normal, mais important.  | 
                    
| 
                             info  | 
                        
                             Informations.  | 
                    
| 
                             debug  | 
                        
                             Messages de débogage.  | 
                    
Le niveau de journalisation par défaut est warn. Un
		serveur en production ne doit pas s'exécuter en mode
		debug, mais augmenter le niveau de détail dans le
		journal des erreurs peut s'avérer utile pour résoudre
		certains problèmes. A partir de la
		version 2.3.8, la directive 
                  Dans cet exemple, l'ensemble du serveur est en mode
		  debug, sauf le module 
Apache httpd garde la trace de toutes les requêtes
		qu'il reçoit dans son journal des accès. En plus de
		l'heure et de la nature d'une requête, httpd peut
		enregistrer l'adresse IP du client, la date et l'heure
		de la requête, le résultat et quantité d'autres
		informations. Les différents formats de journaux sont
		documentés dans le manuel. Le fichier concerne par
		défaut le serveur principal, mais il peut être configuré
		pour chaque serveur virtuel via les directives de
		configuration  
De nombreux programmes libres ou commerciaux permettent d'analyser les journaux d'accès. Analog et Webalyser sont des programmes d'analyse libres parmi les plus populaires. L'analyse des journaux doit s'effectuer hors ligne afin de ne pas surcharger le serveur web avec le traitement des fichiers journaux. La plupart des programmes d'analyse des journaux sont compatibles avec le format de journal "Common". Voici une description des différents champs présents dans une entrée du journal :
195.54.228.42 - - [24/Mar/2007:23:05:11 -0400] "GET /sander/feed/ HTTP/1.1" 200 9747
64.34.165.214 - - [24/Mar/2007:23:10:11 -0400] "GET /sander/feed/atom HTTP/1.1" 200 9068
60.28.164.72 - - [24/Mar/2007:23:11:41 -0400] "GET / HTTP/1.0" 200 618
85.140.155.56 - - [24/Mar/2007:23:14:12 -0400] "GET /sander/2006/09/27/44/ HTTP/1.1" 200 14172
85.140.155.56 - - [24/Mar/2007:23:14:15 -0400] "GET /sander/2006/09/21/gore-tax-pollution/ HTTP/1.1" 200 15147
74.6.72.187 - - [24/Mar/2007:23:18:11 -0400] "GET /sander/2006/09/27/44/ HTTP/1.0" 200 14172
74.6.72.229 - - [24/Mar/2007:23:24:22 -0400] "GET /sander/2006/11/21/os-java/ HTTP/1.0" 200 13457
                | 
                             Champ  | 
                        
                             Contenu  | 
                        
                             Explication  | 
                    
| 
                             Adresse IP client  | 
                        
                             195.54.228.42  | 
                        
                             Adresse IP d'où provient la requête  | 
                    
| 
                             Identité RFC 1413  | 
                        
                             -  | 
                        
                           Identité de l'utilisateur distant renvoyée par son démon identd  | 
                    
| 
                             Nom utilisateur  | 
                        
                             -  | 
                        
                             Nom de l'utilisateur distant issu de l'authentification Apache  | 
                    
| 
                             Horodatage  | 
                        
                             [24/Mar/2007:23:05:11 -0400]  | 
                        
                             Date et heure de la requête  | 
                    
| 
                             Requête  | 
                        
                             "GET /sander/feed/ HTTP/1.1"  | 
                        
                             La requête proprement dite  | 
                    
| 
                             Code d'état  | 
                        
                             200  | 
                        
                             Code d'état renvoyé avec la réponse  | 
                    
| 
                             Contenu en octets  | 
                        
                             9747  | 
                        
                             Total des octets transférés sans les en-têtes  | 
                    
Il y a de nombreuses raisons pour mettre en oeuvre la rotation des fichiers journaux. Même si pratiquement plus aucun système d'exploitation n'impose une limite de taille pour les fichiers de deux GigaOctets, avec le temps, les fichiers journaux deviennent trop gros pour pouvoir être traités. En outre, toute analyse de journal ne doit pas être effectuée sur un fichier dans lequel le serveur est en train d'écrire. Une rotation périodique des fichiers journaux permet de faciliter leur analyse, et de se faire une idée plus précise des habitudes d'utilisation.
Sur les systèmes unix, vous pouvez simplement effectuer cette rotation en changeant le nom du fichier journal via la commande mv. Le serveur continuera à écrire dans le fichier ouvert même s'il a changé de nom. Lorsque vous enverrez un signal de redémarrage "Graceful" au serveur, il ouvrira un nouveau fichier journal avec le nom configuré par défaut. Par exemple, vous pouvez écrire un script de ce style pour cron :
Cette approche fonctionne aussi sous Windows, mais avec moins de souplesse. Alors que le processus httpd de votre serveur sous Windows continuera à écrire dans le fichier journal une fois ce dernier renommé, le service Windows qui exécute Apache n'est pas en mesure d'effectuer un redémarrage graceful. Sous Windows, le redémarrage d'un service consiste simplement à l'arrêter et à le démarrer à nouveau, alors qu'avec un redémarrage graceful, les processus enfants terminent le traitement des requêtes en cours avant de s'arrêter, et le serveur httpd est alors immédiatement à nouveau disponible pour traiter les nouvelles requêtes. Sous Windows, le processus d'arrêt/redémarrage du service interrompt les traitements de requêtes en cours, et le serveur demeure indisponible jusqu'à ce qu'il ait terminé son redémarrage. Vous devez donc tenir compte de toutes ces contraintes lorsque vous planifiez un redémarrage.
                  Une seconde approche consiste à utiliser la
		  redirection des logs. Les directives |) comme dans cet exemple : 
                
Le programme cible de la redirection recevra alors les données de journalisation d'Apache sur son entrée standard stdin, et pourra en faire ce qu'il voudra. Le programme rotatelogs fourni avec Apache effectue une rotation des journaux de manière transparente en fonction du temps ou de la quantité de données écrites, et archive l'ancien fichier journal en ajoutant un suffixe d'horodatage à son nom. Cependant, si cette méthode fonctionne de manière satisfaisante sur les plateformes de style unix, il n'en est pas de même sous Windows.
L'écriture d'entrées dans les fichiers journaux est consommatrice de ressources, mais l'importance de ces données est telle qu'il est fortement déconseillé de désactiver la journalisation. Pour optimiser les performances, vous devez enregistrer vos journaux sur un disque physique différent de celui où se situe votre site web car les modes d'accès sont très différents. La lecture de données sur un disque possède un caractère essentiellement aléatoire, alors que l'écriture dans les fichiers journaux s'effectue de manière séquentielle.
                  Ne définissez jamais la directive 
Si votre serveur possède plus d'un serveur virtuel,
		il est conseillé d'attribuer un journal des accès séparé à
		chacun d'entre eux, ce qui a pour effet de faciliter son
		exploitation ultérieure. Par contre, si votre serveur
		possède un grand nombre de serveurs virtuels, le nombre
		de fichiers journaux à ouvrir va représenter une
		consommation de ressources importante pour votre
		système, et il sera peut-être alors plus judicieux
		d'utiliser un seul fichier journal avec l'aménagement
		suivant : utiliser l'élément de format %v
		en tête de votre directive support/split-logfile.
                
                    Vous pouvez aussi utiliser la directive 
Il est interessant de mettre en oeuvre une charge de test afin d'évaluer les performances du système en conditions réelles de fonctionnement. A cet effet, il existe des paquets commerciaux comme LoadRunner, mais aussi de nombreux outils libres permettant de générer une charge de test pour votre serveur web.
Des projets externes à l'ASF et réputés relativement corrects : grinder, httperf, tsung, FunkLoad.
Lorsque vous appliquez une charge de test à votre serveur web, gardez à l'esprit que si ce dernier est en production, la charge de test peut en affecter négativement les performances. En outre, le transfert de données supplémentaires induit peut être comptabilisé dans le quota mensuel qui vous a été éventuellement alloué.
httpd version 2.2 est par défaut un serveur web avec des
	    processus enfants lancés au préalable. Au démarrage du
	    serveur, le processus parent lance un certain nombre de
	    processus enfants et ce sont eux qui seront chargés de traiter les
	    requêtes. Mais avec httpd version 2.0 est apparu le concept
	    de module multi-process (MPM). Les développeurs purent alors
	    écrire des MPMs qui pouvaient fonctionner avec l'architecture
	    à base de processus ou de threads de leur système
	    d'exploitation spécifique. Apache 2 est fourni avec des MPMs
	    spécifiques pour Windows, OS/2, Netware et BeOS. Pour les
	    plateformes de style unix, les deux MPMS les plus connus
	    sont Prefork et Worker. Le MPM Prefork offre le même modèle
	    de processus enfants prélancés que celui d'Apache 1.3. Le
	    MPM Worker quant à lui, lance un nombre de processus enfants
	    moins important, mais attribue à chacun d'entre eux un
	    certain nombre de threads pour traiter les requêtes. Avec la
	    version 2.4, le MPM n'est plus défini à la compilation,
	    mais peut être chargé à l'exécution via la directive
	    
Le nombre maximum de process, à savoir le nombre de processus enfants prélancés et/ou de threads, donne une approximation du nombre de requêtes que votre serveur peut traiter simultanément. Ce n'est cependant qu'une estimation car le noyau peut mettre en file d'attente des tentatives de connexion à votre serveur. Lorsque votre site approche de la saturation et si le nombre maximum de process est atteint, la machine n'impose pas de limite absolue au delà de laquelle les clients se verront refuser l'accès. Cependant, lorsque les requêtes commencent à être mises en file d'attente, les performances du système se dégradent rapidement.
Enfin, si le serveur httpd en question n'exécute aucun
	    code tiers via mod_php, mod_perl,
	    etc..., nous recommandons l'utilisation de
	    
La directive MaxClients permet de
		spécifier le nombre maximum de process que votre serveur
		pourra créer. Deux autres directives lui sont associées
		: MinSpareServers et
		MaxSpareServers, qui permettent d'encadrer
		le nombre de process que httpd garde en réserve pour
		traiter les requêtes. Le nombre total de process que
		httpd peut créer peut
		être défini via la directive ServerLimit. 
                
Les directives ci-dessus suffisent pour définir les
		limites des nombres de process dans le cas du MPM Prefork.
		Cependant, si vous utilisez un MPM à base de threads, la
		situation est un peu plus compliquée. Les MPMs à base de
		threads supportent la directive
		ThreadsPerChild. httpd impose le fait que
		MaxClients doit être divisible par
		ThreadsPerChild. Si les valeurs que vous
		attribuez à ces deux directives ne respectent pas cette
		règle, httpd affichera un message d'erreur et corrigera
		la valeur de la directive ThreadsPerChild
		en la diminuant jusqu'à ce que la valeur de la directive
		MaxClients soit divisible par elle.
                
Idéalement, le nombre maximum de processus devrait
		être choisi de façon à ce que toute la mémoire système
		soit utilisée, sans la dépasser. En effet, si votre
		système est surchargé au point de devoir faire appel de
		manière intensive au swap (utilisation de la mémoire
		disque), les performances vont se dégrader rapidement.
		La formule permettant de déterminer la valeur de
		
L'observation est la meilleure manière de déterminer les différentes quantités de mémoire allouées au système, aux programmes externes et aux processus httpd : à cet effet, vous pouvez utiliser les commandes top et free décrites plus haut pour étudier l'empreinte mémoire du système lorsque le serveur web n'est pas en cours d'exécution. Vous pouvez aussi étudier l'empreinte d'un processus type du serveur web via la commande top ; en effet, la plupart des implémentations de cette commande présentent une colonne Mémoire résidente (RSS - Resident Size) et Mémoire partagée (Shared Memory).
La différence entre ces deux colonnes est la quantité de mémoire par processus. Le segment de mémoire partagée n'existe effectivement qu'une seule fois, et est utilisé par le code et les bibliothèques chargées et la concurrence inter-processus (ou tableau de résultat - scoreboard) géré par Apache. La quantité de mémoire utilisée par chaque processus dépend fortement du nombre et du type de modules utilisés. La meilleure façon d'en déterminer les besoins consiste à générer une charge type pour votre site web et à observer l'importance que prennent les processus httpd.
La RAM pour les programmes externes comprend
		principalement la mémoire utilisée pour les programmes
		CGI et les scripts qui s'exécutent indépendamment des
		processus httpd. Par contre, si vous utilisez une
		machine virtuelle Java qui exécute Tomcat sur le même
		serveur, cette dernière va aussi nécessiter une quantité
		de mémoire significative. En conséquence, la formule
		ci-dessus qui sert à calculer la valeur maximale de
		MaxClients permet d'effectuer une première approche,
		mais ne constitue en aucun cas une science exacte. En
		cas de doute, soyez pragmatique et utilisez une valeur assez
		basse pour MaxClients. Le noyau Linux
		réserve une certaine quantité de mémoire pour la mise en
		cache des accès disque. Sous Solaris par contre, il faut disposer
		de suffisamment de mémoire RAM pour créer un processus,
		et si ce n'est pas le cas, httpd va démarrer avec un
		message d'erreur du style "No space left on device" dans
		le journal des erreurs, et sera incapable de créer
		d'autres processus httpd enfants ; une valeur trop
		élevée pour MaxClients constituera alors
		réellement un désavantage. 
                
La commutation entre threads est plus aisée pour le système, et ceux-ci consomment moins de ressources que les processus ; c'est la raison principale pour laquelle il est recommandé de choisir un MPM threadé. Et ceci est encore plus flagrant pour certains systèmes d'exploitation que pour d'autres. Par exemple, sous Solaris ou AIX, la manipulation des processus est assez lourde en termes de ressources système ; l'utilisation d'un MPM threadé est donc tout à fait indiquée pour ces systèmes. Sous Linux en revanche, l'implémentation des threads utilise en fait un processus par thread. Les processus Linux sont assez légers, mais cela signifie qu'un MPM threadé présentera ici un gain en performance moindre que sous d'autres systèmes.
Dans certaines situations cependant, l'utilisation d'un MPM threadé peut induire des problèmes de stabilité. Par exemple, si un processus enfant du MPM prefork se crashe, au plus une connexion client sera affectée ; par contre, si un processus enfant threadé se crashe, ce sont tous les threads de ce processus qui vont se crasher à leur tour, ce qui signifie que tous les clients qui étaient servis par ce processus verront leur connexion interrompue. De plus, certains problèmes de sécurité des threads ("thread-safety") peuvent apparaître, particulièrement avec les bibliothèques tierces. Avec les applications threadées, les différents threads peuvent avoir accès aux mêmes variables sans distinction, sans savoir si une variable n'a pas été modifiée par un autre thread.
Ce problème a fait l'objet d'un point sensible au sein de la communauté PHP car Le processeur PHP repose fortement sur des bibliothèques tierces, et il n'est pas garanti que la totalité d'entre elles soient "thread-safe". Bonne nouvelle cependant : si vous exécutez Apache sous Linux, vous pouvez utiliser PHP avec le MPM prefork sans craindre une diminution de performance trop importante par rapport à une option threadée.
Apache httpd maintient un verrou inter-processus du
		point de vue de son écoute du réseau. Dans les faits,
		cela signifie qu'un seul processus httpd enfant à la
		fois peut recevoir une requête. Ainsi, soient les autres
		processus en profitent alors pour traiter les requêtes
		qu'ils ont déjà reçues, soient ils attendent de pouvoir
		à leur tour récupérer le verrou et ainsi écouter le
		réseau pour recevoir une nouvelle requête. Ceci peut se
		voir comme une porte tournante par laquelle un seul
		processus peut passer à la fois. Sur un serveur web
		fortement chargé où les requêtes arrivent constamment,
		la porte tourne rapidement et les requêtes sont
		acceptées à un rythme soutenu. Sur un serveur faiblement
		chargé en revanche, le processus qui "détient"
		le verrou est suceptible de garder sa porte ouverte un
		certain temps durant lequel tous les autres processus
		seront inactifs, attendant de pouvoir s'approprier le
		verrou. Dans une telle situation, le processus parent
		pourra décider d'arrêter quelques processus enfants en
		fonction de la valeur de la directive
		MaxSpareServers.
La fonction de l'"accept mutex" (c'est le nom donné au verrou inter-processus) consiste à gérer la réception des requêtes de manière ordonnée. Si ce verrou est absent, le syndrome de l'"assaut de la foule" peut apparaître.
Imaginez une équipe de football américain en attente devant la ligne de remise en jeu. Si les joueurs se comportaient comme des processus Apache, ils se précipiteraient tous à la fois pour récupérer la balle au signal de la reprise. Un seul d'entre eux y parviendrait, et tous les autres n'auraient plus qu'à se regrouper à nouveau sur la ligne jusqu'à la reprise suivante. Dans cette métaphore, c'est le quaterback qui va jouer le rôle d'"accept mutex" en donnant la balle au joueur approprié.
La transmission d'une telle quantité d'informations représente naturellement beaucoup de travail et, comme une personne intelligente, un serveur intelligent tentera d'éviter cette surcharge dans la mesure du possible, d'où l'idée de la porte tournante. Dans les dernières années, de nombreux systèmes d'exploitation, comme Linux et Solaris, ont développé du code pour éviter le syndrome de l'"assaut de la foule". Apache reconnaît ce code, et si vous n'effectuez qu'une seule écoute du réseau, autrement dit si vous n'utilisez que le serveur principal ou un seul serveur virtuel, Apache n'utilisera pas d'"accept mutex" ; par contre, si vous effectuez plusieurs écoutes du réseau (par exemple si un serveur virtuel sert les requêtes SSL), Apache utilisera un "accept mutex" afin d'éviter les conflits internes.
Vous pouvez manipuler l'"accept mutex" via la
		directive AcceptMutex. Cette dernière
		permet en particulier de fermer l'"accept mutex", mais
		aussi de sélectionner le mécanisme de verrouillage. Les
		mécanismes de verrouillage courants comprennent fcntl,
		les sémaphores System V et le verrouillage par threads.
		Tous ne sont pas supportés par toutes les plateformes,
		et leur disponibilité dépend aussi des options de
		compilation. Les différents mécanismes de verrouillage
		peuvent avoir des exigences particulières en matière de
		ressources système ; il est donc recommandé de les
		utiliser avec précautions. 
                
Il n'existe aucune raison particulière pour désactiver l'"accept mutex". Apache détermine automatiquement s'il doit utiliser ou non mutex sur votre plateforme en fonction du nombre d'écoutes réseau de votre serveur, comme décrit précédemment.
Souvent, les utilisateurs recherchent le paramètre magique qui va multiplier par quatre les performances de leur système. En fait, les systèmes de type Unix actuels sont déjà optimisés à l'origine, et il n'y a plus grand chose à faire pour améliorer leurs performances. L'administrateur peut cependant encore effectuer quelques modifications qui permettront de peaufiner la configuration.
Le leitmotiv en matière de mémoire est souvent "plus on en a, mieux c'est". En effet, comme nous avons dit plus haut, la mémoire inutilisée peut être avantageusement utilisée comme cache du système de fichiers. Plus vous chargez de modules, plus les processus Apache grossissent, et ceci d'autant plus si vous utilisez des modules qui génèrent des contenus dynamiques comme PHP et mod_perl. Un gros fichier de configuration - avec de nombreux serveurs virtuels - a aussi tendance à augmenter l'empreinte mémoire des processus. Une quantité de mémoire importante vous permettra d'exécuter Apache avec plus de processus enfants, et donc de traiter d'avantage de requêtes simultanément.
Même si les différentes plateformes traitent leur mémoire virtuelle de différentes manières, il est déconseillé de configurer un espace disque de swap inférieur à la mémoire RAM. En effet, le système de mémoire virtuelle a été conçu de manière à prendre le relai lorsque la mémoire RAM fait défaut, et lorsque l'espace disque, et donc l'espace de swap vient à manquer, votre serveur risque de s'arrêter. Vous devrez alors redémarrer physiquement votre serveur, et votre hébergeur pourra vous facturer le service.
Evidemment, ce genre problème survient au moment le
		plus défavorable : lorsque le monde vient découvrir votre
		site web et se présente avec insistance à votre porte.
		Si votre espace de swap est suffisant, même si la
		machine sera de plus en plus surchargée et deviendra
		très très lente car le système devra swapper les pages
		entre la mémoire et le disque, lorsque la charge diminuera à
		nouveau, le système reviendra dans son mode de
		fonctionnement normal. Rappelez-vous que vous disposez
		de la directive MaxClients pour garder le contrôle.
                
La plupart des systèmes de type Unix utilisent des
		partitions dédiées au swap. Au démarrage du système,
		celui-ci enregistre toutes les partitions de swap du ou
		des disques en fonction du type de la partition ou du
		contenu du fichier /etc/fstab et les
		active de manière automatique. Lorsque vous ajoutez un
		disque, ou lorsque vous installez le système
		d'exploitation, assurez-vous d'allouer suffisamment
		d'espace de swap afin de rester en adéquation avec une
		éventuelle augmentation de la mémoire RAM. La
		réallocation d'espace disque sur un système en
		production est en effet pénible et fastidieuse. 
                
Prévoyez un espace de swap de deux fois la taille de
		votre mémoire RAM, et même jusqu'à quatre fois lorsque
		les surcharges peuvent s'avérer fréquentes. Assurez-vous
		de réajuster ces valeurs lorsque vous augmentez la
		quantité de mémoire RAM de votre système. En secours,
		vous pouvez aussi utilisez un fichier comme espace de
		swap. Pour ce faire, vous trouverez les instructions
		dans les pages de manuel de mkswap et
		swapon, ou dans celles des programmes de
		swap. 
                
Supposons que vous disposiez d'une machine possédant une énorme quantité de mémoire RAM et un processeur aux performances astronomiques ; vous pourrez alors exécuter des centaines de processus Apache selon vos besoins, mais tout en restant en deçà des limites imposées par le noyau de votre système.
Considérez maintenant une situation où plusieurs centaines de serveurs web sont en cours d'exécution ; si certains d'entre eux doivent à leur tour lancer des processus CGI, le nombre maximum de processus autorisé par le noyau sera vite atteint.
Dans ce cas, vous pouvez modifier cette limite avec la commande :
Cette modification doit être effectuée avant le
		démarrage du serveur, car la nouvelle valeur ne sera
		prise en compte que dans le shell courant et pour les
		programmes lancés depuis ce dernier. Dans les derniers
		noyaux Linux, la valeur par défaut a été fixée à 2048.
		Sous FreeBSD, ce nombre semble être limité à la valeur
		inhabituelle de 513. Dans le shell par défaut de ce
		système, csh, la commande équivalente est
		limit et possède une syntaxe analogue à
		celle de la commande de style Bourne ulimit :
                
En outre, le noyau peut limiter le nombre de fichiers ouverts par processus. Ce n'est généralement pas un problème pour les serveurs dont les processus sont lancés à l'avance, et où chacun de ceux-ci ne traite qu'une requête à la fois. Les processus des serveurs threadés, quant à eux, traitent plusieurs requêtes simultanément, et sont d'avantage susceptibles de dépasser la limite du nombre de descripteurs de fichiers. Vous pouvez alors augmenter cette valeur limite du nombre de fichiers ouverts avec la commande :
Là encore, cette modification doit être effectuée avant le démarrage du serveur Apache.
Sous Linux, vous pouvez définir les paramètres de
		ulimit au démarrage en éditant le fichier
		/etc/security/limits.conf. Ce fichier vous
		permet de définir des limites "soft" et "hard"
		en fonction de l'utilisateur ou du groupe ;
		vous y trouverez aussi des commentaires explicatifs des
		différentes options. Pour que ce fichier soit pris en
		compte, le fichier /etc/pam.d/login doit
		contenir la ligne : 
                
Chaque item peut posséder une valeur "soft" et "hard" : la première est la valeur par défaut, et la seconde la valeur maximale de cet item.
Dans le fichier /etc/login.conf de
		FreeBSD, ces valeurs peuvent être limitées ou étendues à
		tout le système de manière analogue au fichier
		limits.conf. Les limites "soft" sont
		spécifiées via le paramètre -cur, et les
		limites "hard" via le paramètre -max.
                
Solaris possède un mécanisme similaire pour manipuler
		les valeurs limites au démarrage du système : dans le
		fichier /etc/system, vous pouvez définir au
		démarrage des paramètres du noyau valables pour
		l'ensemble du système. Ce sont les mêmes paramètres que
		ceux définis à l'exécution par le débogueur de noyau
		mdb. Les commandes équivalentes à ulimit -u
		pour définir les limites hard et soft seront du style : 
                
Solaris calcule le nombre maximal de processus
		autorisé par utilisateur (maxuprc) en
		fonction de la mémoire système disponible
		(maxusers). Vous pouvez obtenir ces valeurs
		avec la commande : 
                
Il est cependant déconseillé de les modifier.
Dans la plupart des distributions Unix et Linux, de nombreux services sont activés par défaut, et vous n' avez probablement besoin que d'une minorité d'entre eux. Par exemple, votre serveur web n'a pas besoin de sendmail, de fournir le service NFS, etc... Désactivez les tout simplement.
Pour ce faire, sous RedHat Linux, vous
		disposez de l'utilitaire chkconfig en ligne de commande.
		Sous Solaris, les commandes svcs et
		svcadm vous permettent respectivement
		de lister les services activés et de désactiver ceux
		dont vous n'avez pas besoin. 
                
Vous devez aussi prêter attention aux modules Apache
		chargés par défaut. La plupart des distributions binaires
		d'Apache httpd et des versions préinstallées fournies
		avec les distributions de Linux chargent les modules
		Apache via la directive
		
Les modules inutilisés peuvent être désactivés : si
		vous n'avez pas besoin de leurs fonctionnalités et des
		directives de configuration qu'ils implémentent,
		désactivez-les en commentant les lignes
		
Les requêtes impliquant des contenus dynamiques nécessitent en général d'avantage de ressources que les requêtes pour des contenus statiques. Les contenus statiques consistent en simples pages issues de documents ou images sur disque, et sont servis très rapidement. En outre, de nombreux systèmes d'exploitation mettent automatiquement en cache en mémoire les contenus des fichiers fréquemment accédés.
Comme indiqué précédemment, le traitement des requêtes dynamiques peut nécessiter beaucoup plus de ressources. L'exécution de scripts CGI, le transfert de requêtes à un serveur d'applications externe, ou les accès à une base de données peuvent impliquer des temps d'attente et charges de travail significatifs pour un serveur web fortement sollicité. Dans de nombreuses circonstances, vous pourrez alors améliorer les performances en transformant les requêtes dynamiques courantes en requêtes statiques. Pour ce faire, deux approches seront discutées dans la suite de cette section.
En générant à l'avance les réponses pour les requêtes les plus courantes de votre application, vous pouvez améliorer de manière significative les performances de votre serveur sans abandonner la flexibilité des contenus générés dynamiquement. Par exemple, si votre application est un service de livraison de fleurs, vous aurez tout intérêt à générer à l'avance les pages de votre catalogue concernant les roses rouges dans les semaines précédant le jour de la Saint Valentin. Lorsqu'un utilisateur cherchera des roses rouges, il téléchargera alors les pages générées à l'avance. Par contre, les recherches de roses jaunes seront quant à elles traitées directement via une requête vers la base de données. Pour effectuer ces aiguillages de requêtes, vous disposez d'un outil particulièrement approprié fourni avec Apache : le module mod_rewrite.
Blosxom est un programme CGI de journalisation web léger. Il est écrit en Perl et utilise des fichiers texte pour ses entrées. Outre sa qualité de programme CGI, Blosxom peut être exécuté en ligne de commande pour générer à l'avance des pages de blog. Lorsque votre blog commence à être lu par un grand nombre de personnes, la génération à l'avance de pages en HTML satique peut améliorer de manière significative les performances de votre serveur.
Pour générer des pages statiques avec blosxom, éditez
		le script CGI selon la documentation. Définissez la
		variable $static dir à la valeur de
		
Vous pouvez exécuter ce script périodiquement via
		cron, à chaque fois que vous ajoutez un nouveau contenu. Pour
		faire en sorte qu'Apache substitue les pages
		statiques au contenu dynamique, nous
		utiliserons mod_rewrite. Ce module est fourni avec le
		code source d'Apache, mais n'est pas compilé par défaut.
		Pour le compiler avec la distribution d'Apache, vous
		pouvez utiliser l'option de la commande configure
		--enable-rewrite[=shared]. De nombreuses
		distributions binaires d'Apache sont fournies avec
		
                    Si les directives 
Le module mod_cache implémente une mise en cache intelligente des réponses HTTP : il tient compte des délais de péremption et des contraintes en matière de contenu inhérentes à la spécification HTTP. Le module mod_cache met en cache les URL des contenus des réponses. Si un contenu envoyé au client peut être mis en cache, il est sauvegardé sur disque. Les requêtes ultérieures pour cette URL seront alors servies directement depuis le cache. Le module fournisseur pour mod_cache, mod_disk_cache, détermine la manière dont les contenus sont stockés sur disque. La plupart des systèmes de serveur possèdent plus d'espace disque que de mémoire, et il est bon de garder à l'esprit que certains noyaux système mettent en cache de manière transparente en mémoire les contenus sur disque fréquemment accédés ; il n'est donc pas très utile de répéter cette opération au niveau du serveur.
Pour mettre en oeuvre une mise en cache de contenu
	    efficace et éviter de présenter à l'utilisateur un contenu
	    invalide ou périmé, l'application qui génère le contenu à
	    jour doit envoyer les en-têtes de réponse corrects. En
	    effet, en l'absence d'en-têtes comme Etag:,
	    Last-Modified: ou Expires:,
	    --enable-cache[=shared] du
	    script configure. Si vous utilisez une distribution binaire
	    d'Apache httpd, ou si elle fait partie de votre portage ou
	    de votre sélection de paquets, 
                    Le Wiki de l'Apache Software Foundation est servi
		    par MoinMoin. MoinMoin est écrit en Python et
		    s'exécute en tant que programme CGI. A l'heure
		    actuelle, toute tentative pour l'exécuter via
		    mod_python s'est soldée par un échec. Le programme
		    CGI induit une charge inacceptable sur le serveur,
		    particulièrement lorsque le Wiki est indexé par des
		    moteurs de recherche comme Google. Pour alléger la
		    charge de la machine, l'équipe d'infrastructure
		    d'Apache s'est tournée vers mod_cache. Il s'est
		    avéré que MoinMoin
		    nécessitait un petit patch pour adopter un
		    comportement approprié en aval du serveur de mise
		    en cache : certaines requêtes ne pouvaient jamais
		    être mises en cache, et les modules Python
		    concernés ont été mis à jour pour pouvoir envoyer
		    les en-têtes de réponse HTTP corrects. Après cette
		    modification, la mise en cache en amont du Wiki a
		    été activée via l'insertion des lignes suivantes
		    dans le fichier de configuration
		    httpd.conf :
                
Cette configuration essaie de mettre en cache tout
		contenu de son serveur virtuel. Elle ne mettra jamais en
		cache un contenu plus vieux que 6 heures (voir la
		directive Expires: est absent de la
		réponse, Last-Modified:. Le principe de ce calcul
		qui utilise la directive 
                    Notez qu'il peut s'avérer payant de
		    désactiver l'en-tête ETag: :
		    pour les fichiers inférieurs à 1 ko, le serveur
		    doit calculer la somme de vérification checksum (en
		    général MD5) et envoyer une réponse 304 Not
		    Modified, ce qui utilise des ressources CPU
		    et réseau pour le transfert (1 paquet TCP). Pour les
		    ressources supérieures à 1 ko, les ressources CPU
		    consommées peuvent devenir importantes car l'en-tête
		    est calculé à chaque requête. Malheureusement, il
		    n'existe actuellement aucun moyen pour mettre en
		    cache ces en-têtes. 
                
                    Dans l'exemple précédent: la génération d'un en-tête
		    ETag: sera désactivée pour la plupart
		    des ressources statiques. Le serveur ne génère pas
		    ces en-têtes pour les ressources dynamiques. 
                
Armés du savoir-faire pour personnaliser un système afin qu'il affiche les performances désirées, nous découvrirons vite qu'1 sytème à lui seul peut constituer un goulot d'étranglement. A ce sujet, la page du Wiki PerformanceScalingOut décrit comment adapter un système à mesure qu'il prend de l'ampleur, ou comment personnaliser plusieurs systèmes dans leur ensemble.