mirror of
				https://github.com/apache/httpd.git
				synced 2025-10-31 19:10:37 +03:00 
			
		
		
		
	git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1384385 13f79535-47bb-0310-9956-ffa450edef68
		
			
				
	
	
		
			1074 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1074 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| <?xml version="1.0" encoding="ISO-8859-1" ?>
 | |
| <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
 | |
| <?xml-stylesheet type="text/xsl" href="../style/manual.fr.xsl"?>
 | |
| <!-- English Revision : 1379836 -->
 | |
| <!-- French translation : Lucien GENTIS -->
 | |
| <!-- Reviewed by : Vincent Deffontaines -->
 | |
| 
 | |
| <!--
 | |
|  Licensed to the Apache Software Foundation (ASF) under one or more
 | |
|  contributor license agreements.  See the NOTICE file distributed with
 | |
|  this work for additional information regarding copyright ownership.
 | |
|  The ASF licenses this file to You under the Apache License, Version 2.0
 | |
|  (the "License"); you may not use this file except in compliance with
 | |
|  the License.  You may obtain a copy of the License at
 | |
| 
 | |
|      http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|  Unless required by applicable law or agreed to in writing, software
 | |
|  distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  See the License for the specific language governing permissions and
 | |
|  limitations under the License.
 | |
| -->
 | |
| 
 | |
| <manualpage metafile="perf-tuning.xml.meta">
 | |
|   <parentdocument href="./">Documentations diverses</parentdocument>
 | |
| 
 | |
|   <title>Optimisation des performances d'Apache</title>
 | |
| 
 | |
|   <summary>
 | |
| 
 | |
|     <p>Apache 2.x est un serveur web à usage général, conçu dans un but
 | |
|     d'équilibre entre souplesse, portabilité et performances. Bien que non
 | |
|     conçu dans le seul but d'établir une référence en la matière,
 | |
|     Apache 2.x est capable de hautes performances dans de nombreuses situations
 | |
|     du monde réel.</p>
 | |
| 
 | |
|     <p>Comparée à Apache 1.3, la version 2.x comporte de nombreuses
 | |
|     optimisations supplémentaires permettant d'améliorer le débit du serveur
 | |
|     et sa personnalisation. La plupart de ces améliorations sont activées par
 | |
|     défaut. Cependant, certains choix de configuration à la compilation et à
 | |
|     l'exécution peuvent affecter les performances de manière significative. Ce
 | |
|     document décrit les options qu'un administrateur de serveur peut configurer
 | |
|     pour améliorer les performances d'une installation d'Apache 2.x. Certaines
 | |
|     de ces options de configuration permettent au démon httpd de mieux tirer
 | |
|     parti des possibilités du matériel et du système d'exploitation, tandis
 | |
|     que d'autres permettent à l'administrateur de privilégier la vitesse
 | |
|     par rapport aux fonctionnalités.</p>
 | |
| 
 | |
|   </summary>
 | |
| 
 | |
|   <section id="hardware">
 | |
| 
 | |
|     <title>Problèmes matériels et relatifs au système d'exploitation</title>
 | |
| 
 | |
|     <p>Le principal problème matériel qui affecte les performances du serveur
 | |
|     web est la mémoire vive (RAM). Un serveur web ne devrait jamais avoir à
 | |
|     utiliser le swap, car le swapping augmente le temps de réponse de chaque
 | |
|     requête au delà du point que les utilisateurs considèrent comme
 | |
|     "trop lent". Ceci incite les utilisateurs à cliquer sur "Stop", puis
 | |
|     "Charger à nouveau", ce qui a pour effet d'augmenter encore la charge
 | |
|     du serveur. Vous pouvez, et même devez définir la valeur de la directive
 | |
|     <directive module="mpm_common">MaxRequestWorkers</directive> de façon à ce que
 | |
|     votre serveur ne lance pas un nombre de processus enfants tel qu'il
 | |
|     commence à faire du swapping. La méthode pour y parvenir est
 | |
|     simple : déterminez la taille de votre processus Apache standard en
 | |
|     consultant votre liste de processus à l'aide d'un outil tel que
 | |
|     <code>top</code>, et divisez votre quantité totale de mémoire disponible
 | |
|     par cette taille, tout en gardant un espace suffisant
 | |
|     pour les autres processus.</p>
 | |
| 
 | |
|     <p>Hormis ce réglage relatif à la mémoire, le reste est trivial : le
 | |
|     processeur, la carte réseau et les disques doivent être suffisamment
 | |
|     rapides, où "suffisamment rapide" doit être déterminé par
 | |
|     l'expérience.</p>
 | |
| 
 | |
|     <p>Le choix du système d'exploitation dépend principalement du
 | |
|     contexte local. Voici cependant quelques conseils qui se sont
 | |
|     généralement avérés utiles :</p>
 | |
| 
 | |
|     <ul>
 | |
|       <li>
 | |
|         <p>Exécutez la dernière version stable et le niveau de patches le
 | |
| 	plus haut du système d'exploitation que vous avez choisi. De nombreux
 | |
| 	éditeurs de systèmes d'exploitation ont amélioré de manière
 | |
| 	significative les performances de leurs piles TCP et de leurs
 | |
| 	bibliothèques de thread ces dernières années.</p>
 | |
|       </li>
 | |
| 
 | |
|       <li>
 | |
|         <p>Si votre système d'exploitation possède un appel système
 | |
| 	<code>sendfile(2)</code>, assurez-vous d'avoir installé la version
 | |
| 	et/ou les patches nécessaires à son activation. (Pour Linux, par
 | |
| 	exemple, cela se traduit par Linux 2.4 ou plus. Pour les versions
 | |
| 	anciennes de Solaris 8, vous pouvez être amené à appliquer un patch.)
 | |
| 	Sur les systèmes où il est disponible, <code>sendfile</code> permet
 | |
| 	à Apache 2 de servir les contenus statiques plus rapidement, tout en
 | |
| 	induisant une charge CPU inférieure.</p>
 | |
|       </li>
 | |
|     </ul>
 | |
| 
 | |
|   </section>
 | |
| 
 | |
|   <section id="runtime">
 | |
| 
 | |
|     <title>Optimisation de la configuration à l'exécution</title>
 | |
| 
 | |
|     <related>
 | |
|       <modulelist>
 | |
|         <module>mod_dir</module>
 | |
|         <module>mpm_common</module>
 | |
|         <module>mod_status</module>
 | |
|       </modulelist>
 | |
|       <directivelist>
 | |
|         <directive module="core">AllowOverride</directive>
 | |
|         <directive module="mod_dir">DirectoryIndex</directive>
 | |
|         <directive module="core">HostnameLookups</directive>
 | |
|         <directive module="core">EnableMMAP</directive>
 | |
|         <directive module="core">EnableSendfile</directive>
 | |
|         <directive module="core">KeepAliveTimeout</directive>
 | |
|         <directive module="prefork">MaxSpareServers</directive>
 | |
|         <directive module="prefork">MinSpareServers</directive>
 | |
|         <directive module="core">Options</directive>
 | |
|         <directive module="mpm_common">StartServers</directive>
 | |
|       </directivelist>
 | |
|     </related>
 | |
| 
 | |
|     <section id="dns">
 | |
| 
 | |
|       <title>HostnameLookups et autres considérations à propos du DNS</title>
 | |
| 
 | |
|       <p>Avant Apache 1.3, la directive
 | |
|       <directive module="core">HostnameLookups</directive> était positionnée
 | |
|       par défaut à <code>On</code>. Ce réglage augmente le temps de réponse de
 | |
|       chaque requête car il entraîne une recherche DNS et le traitement de la
 | |
|       requête ne pourra pas être achevé tant que cette recherche ne sera
 | |
|       pas terminée. Avec Apache 1.3, ce réglage est défini par défaut à
 | |
|       <code>Off</code>. Si vous souhaitez que les adresses dans vos fichiers
 | |
|       journaux soient résolues en noms d'hôtes, utilisez le programme
 | |
|       <program>logresolve</program> fourni avec Apache, ou un des nombreux
 | |
|       paquets générateurs de rapports sur les journaux disponibles.</p>
 | |
| 
 | |
|       <p>Il est recommandé d'effectuer ce genre de traitement a posteriori
 | |
|       de vos fichiers journaux sur une autre machine que celle qui héberge le
 | |
|       serveur web en production, afin que cette activité n'affecte pas les
 | |
|       performances du serveur.</p>
 | |
| 
 | |
|       <p>Si vous utilisez une directive
 | |
|       <code><directive module="mod_access_compat">Allow</directive>from domain</code>
 | |
|       ou
 | |
|       <code><directive module="mod_access_compat">Deny</directive> from domain</code>
 | |
|       (ce qui signifie que vous utilisez un nom d'hôte ou un nom de domaine à
 | |
|       la place d'une adresse IP), vous devrez compter avec deux recherches
 | |
|       DNS (une recherche inverse suivie d'une recherche directe pour
 | |
|       s'assurer que l'adresse IP n'a pas été usurpée). C'est pourquoi il est
 | |
|       préférable, pour améliorer les performances, d'utiliser des adresses IP
 | |
|       plutôt que des noms lorsqu'on utilise ces directives, du moins chaque
 | |
|       fois que c'est possible.</p>
 | |
| 
 | |
|       <p>Notez qu'il est possible de modifier la portée des directives, en les
 | |
|       plaçant par exemple à l'intérieur d'une section
 | |
|       <code><Location /server-status></code>. Les recherches DNS ne
 | |
|       seront alors effectuées que pour les requêtes qui satisfont aux critères.
 | |
|       Voici un exemple qui désactive les recherches DNS sauf pour les fichiers
 | |
|       <code>.html</code> et <code>.cgi</code> :</p>
 | |
| 
 | |
|       <highlight language="config">
 | |
| HostnameLookups off
 | |
| <Files ~ "\.(html|cgi)$">
 | |
|   HostnameLookups on
 | |
| </Files>
 | |
|       </highlight>
 | |
| 
 | |
|       <p>Mais même dans ce cas, si vous n'avez besoin de noms DNS que dans
 | |
|       certains CGIs, vous pouvez effectuer l'appel à <code>gethostbyname</code>
 | |
|       dans les CGIs spécifiques qui en ont besoin.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section id="symlinks">
 | |
| 
 | |
|       <title>FollowSymLinks et SymLinksIfOwnerMatch</title>
 | |
| 
 | |
|       <p>Chaque fois que la ligne <code>Options FollowSymLinks</code> sera
 | |
|       absente, ou que la ligne <code>Options SymLinksIfOwnerMatch</code> sera
 | |
|       présente dans votre espace d'adressage, Apache devra effectuer des
 | |
|       appels système supplémentaires pour vérifier la présence de liens
 | |
|       symboliques. Un appel supplémentaire par élément du chemin du fichier.
 | |
|       Par exemple, si vous avez :</p>
 | |
| 
 | |
|       <highlight language="config">
 | |
| DocumentRoot /www/htdocs
 | |
| <Directory />
 | |
|   Options SymLinksIfOwnerMatch
 | |
| </Directory>
 | |
|       </highlight>
 | |
| 
 | |
|       <p>et si une requête demande l'URI <code>/index.html</code>, Apache
 | |
|       effectuera un appel à <code>lstat(2)</code> pour
 | |
|       <code>/www</code>, <code>/www/htdocs</code>, et
 | |
|       <code>/www/htdocs/index.html</code>. Les résultats de ces appels à
 | |
|       <code>lstat</code> ne sont jamais mis en cache, ils devront donc être
 | |
|       générés à nouveau pour chaque nouvelle requête. Si vous voulez absolument
 | |
|       vérifier la sécurité des liens symboliques, vous pouvez utiliser une
 | |
|       configuration du style :</p>
 | |
| 
 | |
|       <highlight language="config">
 | |
| DocumentRoot /www/htdocs
 | |
| <Directory />
 | |
|   Options FollowSymLinks
 | |
| </Directory>
 | |
| 
 | |
| <Directory /www/htdocs>
 | |
|   Options -FollowSymLinks +SymLinksIfOwnerMatch
 | |
| </Directory>
 | |
|       </highlight>
 | |
| 
 | |
|       <p>Ceci évite au moins les vérifications supplémentaires pour le chemin
 | |
|       défini par <directive module="core">DocumentRoot</directive>. Notez que
 | |
|       vous devrez ajouter des sections similaires si vous avez des chemins
 | |
|       définis par les directives
 | |
|       <directive module="mod_alias">Alias</directive> ou
 | |
|       <directive module="mod_rewrite">RewriteRule</directive> en dehors de
 | |
|       la racine de vos documents. Pour améliorer les performances, et supprimer
 | |
|       toute protection des liens symboliques, ajoutez l'option
 | |
|       <code>FollowSymLinks</code> partout, et n'utilisez jamais l'option
 | |
|       <code>SymLinksIfOwnerMatch</code>.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section id="htaccess">
 | |
| 
 | |
|       <title>AllowOverride</title>
 | |
| 
 | |
|       <p>Dans toute partie de votre espace d'adressage où vous autoriserez
 | |
|       la surcharge de la configuration (en général à l'aide de fichiers
 | |
|       <code>.htaccess</code>), Apache va tenter d'ouvrir <code>.htaccess</code>
 | |
|       pour chaque élément du chemin du fichier demandé. Par exemple, si vous
 | |
|       avez : </p>
 | |
| 
 | |
|       <highlight language="config">
 | |
| DocumentRoot /www/htdocs
 | |
| <Directory />
 | |
|   AllowOverride all
 | |
| </Directory>
 | |
|       </highlight>
 | |
| 
 | |
|       <p>et qu'une requête demande l'URI <code>/index.html</code>, Apache
 | |
|       tentera d'ouvrir <code>/.htaccess</code>, <code>/www/.htaccess</code>,
 | |
|       et <code>/www/htdocs/.htaccess</code>. Les solutions sont similaires à
 | |
|       celles évoquées précédemment pour <code>Options FollowSymLinks</code>.
 | |
|       Pour améliorer les performances, utilisez <code>AllowOverride None</code>
 | |
|       pour tous les niveaux de votre espace d'adressage.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section id="negotiation">
 | |
| 
 | |
|       <title>Négociation</title>
 | |
| 
 | |
|       <p>Dans la mesure du possible, évitez toute négociation de contenu si
 | |
|       vous tenez au moindre gain en performances. En pratique toutefois,
 | |
|       les bénéfices de la négociation l'emportent souvent sur la diminution
 | |
|       des performances.
 | |
|       Il y a cependant un cas dans lequel vous pouvez accélérer le serveur.
 | |
|       Au lieu d'utiliser une directive générique comme :</p>
 | |
| 
 | |
|       <highlight language="config">DirectoryIndex index</highlight>
 | |
| 
 | |
|       <p>utilisez une liste explicite d'options :</p>
 | |
| 
 | |
|       <highlight language="config">DirectoryIndex index.cgi index.pl index.shtml index.html</highlight>
 | |
| 
 | |
|       <p>où vous placez le choix courant en première position.</p>
 | |
| 
 | |
|       <p>Notez aussi que créer explicitement un fichier de
 | |
|       <code>correspondances de type</code> fournit de meilleures performances
 | |
|       que l'utilisation des <code>MultiViews</code>, car les informations
 | |
|       nécessaires peuvent être simplement obtenues en lisant ce fichier, sans
 | |
|       avoir à parcourir le répertoire à la recherche de types de fichiers.</p>
 | |
| 
 | |
|     <p>Par conséquent, si la négociation de contenu est nécessaire pour votre
 | |
|     site, préférez les fichiers de <code>correspondances de type</code> aux
 | |
|     directives <code>Options MultiViews</code> pour mener à bien cette
 | |
|     négociation. Se référer au document sur la
 | |
|     <a href="../content-negotiation.html">Négociation de contenu</a> pour une
 | |
|     description complète des méthodes de négociation, et les instructions
 | |
|     permettant de créer des fichiers de <code>correspondances de type</code>.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Transfert en mémoire</title>
 | |
| 
 | |
|       <p>Dans les situations où Apache 2.x doit consulter le contenu d'un
 | |
|       fichier en train d'être servi - par exemple à l'occasion du traitement
 | |
|       d'une inclusion côté serveur - il transfère en général le fichier en
 | |
|       mémoire si le système d'exploitation supporte une forme quelconque
 | |
|       de <code>mmap(2)</code>.</p>
 | |
| 
 | |
|       <p>Sur certains systèmes, ce transfert en mémoire améliore les
 | |
|       performances. Dans certains cas, ce transfert peut toutefois les dégrader
 | |
|       et même diminuer la stabilité du démon httpd :</p>
 | |
| 
 | |
|       <ul>
 | |
|         <li>
 | |
|           <p>Dans certains systèmes d'exploitation, <code>mmap</code> devient
 | |
| 	  moins efficace que <code>read(2)</code> quand le nombre de
 | |
| 	  processeurs augmente. Sur les serveurs multiprocesseurs sous Solaris,
 | |
| 	  par exemple, Apache 2.x sert parfois les fichiers consultés par le
 | |
| 	  serveur plus rapidement quand <code>mmap</code> est désactivé.</p>
 | |
|         </li>
 | |
| 
 | |
|         <li>
 | |
|           <p>Si vous transférez en mémoire un fichier localisé dans un système
 | |
| 	  de fichiers monté par NFS, et si un processus sur
 | |
| 	  une autre machine cliente NFS supprime ou tronque le fichier, votre
 | |
| 	  processus peut rencontrer une erreur de bus la prochaine fois qu'il
 | |
| 	  essaiera d'accéder au contenu du fichier en mémoire.</p>
 | |
|         </li>
 | |
|       </ul>
 | |
| 
 | |
|       <p>Pour les installations où une de ces situations peut se produire,
 | |
|       vous devez utiliser <code>EnableMMAP off</code> afin de désactiver le
 | |
|       transfert en mémoire des fichiers servis. (Note : il est possible de
 | |
|       passer outre cette directive au niveau de chaque répertoire.)</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Sendfile</title>
 | |
| 
 | |
|       <p>Dans les cas où Apache peut se permettre d'ignorer le contenu du
 | |
|       fichier à servir - par exemple, lorsqu'il sert un contenu de fichier
 | |
|       statique - il utilise en général le support sendfile du noyau si le
 | |
|       système d'exploitation supporte l'opération <code>sendfile(2)</code>.</p>
 | |
| 
 | |
|       <p>Sur la plupart des plateformes, l'utilisation de sendfile améliore
 | |
|       les performances en éliminant les mécanismes de lecture et envoi séparés.
 | |
|       Dans certains cas cependant, l'utilisation de sendfile peut nuire à la
 | |
|       stabilité du démon httpd :</p>
 | |
| 
 | |
|       <ul>
 | |
|         <li>
 | |
|           <p>Certaines plateformes peuvent présenter un support de sendfile
 | |
| 	  défaillant que la construction du système n'a pas détecté, en
 | |
| 	  particulier si les binaires ont été construits sur une autre machine
 | |
| 	  et transférés sur la machine où le support de sendfile est
 | |
| 	  défaillant.</p>
 | |
|         </li>
 | |
|         <li>
 | |
|           <p>Dans le cas d'un système de fichiers monté
 | |
| 	  sous NFS, le noyau peut s'avérer incapable de servir
 | |
| 	  les fichiers réseau de manière fiable depuis
 | |
| 	  son propre cache.</p>
 | |
|         </li>
 | |
|       </ul>
 | |
| 
 | |
|       <p>Pour les installations où une de ces situations peut se produire,
 | |
|       vous devez utiliser <code>EnableSendfile off</code> afin de désactiver
 | |
|       la mise à disposition de contenus de fichiers par sendfile. (Note : il
 | |
|       est possible de passer outre cette directive au niveau de chaque
 | |
|       répertoire.)</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section id="process">
 | |
| 
 | |
|       <title>Process Creation</title>
 | |
| 
 | |
|       <p>Avant Apache 1.3, les directives
 | |
|       <directive module="prefork">MinSpareServers</directive>,
 | |
|       <directive module="prefork">MaxSpareServers</directive>, et
 | |
|       <directive module="mpm_common">StartServers</directive> avaient des
 | |
|       effets drastiques sur les performances de référence. En particulier,
 | |
|       Apache avait besoin d'un délai de "montée en puissance" afin d'atteindre
 | |
|       un nombre de processus enfants suffisant pour supporter la charge qui lui
 | |
|       était appliquée. Après le lancement initial des processus enfants par
 | |
|       <directive module="mpm_common">StartServers</directive>, seulement un
 | |
|       processus enfant par seconde était créé afin d'atteindre la valeur de la
 | |
|       directive <directive module="prefork">MinSpareServers</directive>. Ainsi,
 | |
|       un serveur accédé par 100 clients simultanés et utilisant la valeur par
 | |
|       défaut de <code>5</code> pour la directive
 | |
|       <directive module="mpm_common">StartServers</directive>, nécessitait
 | |
|       environ 95 secondes pour lancer suffisamment de processus enfants
 | |
|       permettant de faire face à la charge. Ceci fonctionne en pratique pour
 | |
|       les serveurs en production, car ils sont rarement redémarrés. Ce n'est
 | |
|       cependant pas le cas pour les tests de référence (benchmarks) où le
 | |
|       serveur ne fonctionne que 10 minutes.</p>
 | |
| 
 | |
|       <p>La règle "un processus par seconde" avait été implémentée afin
 | |
|       d'éviter l'enlisement de la machine dans le démarrage de nouveaux
 | |
|       processus enfants. Pendant que la machine est occupée à lancer des
 | |
|       processus enfants, elle ne peut pas traiter les requêtes. Mais cette
 | |
|       règle impactait tellement la perception des performances d'Apache qu'elle
 | |
|       a dû être remplacée. A partir d'Apache 1.3, le code a assoupli la règle
 | |
|       "un processus par seconde". Il va en lancer un, attendre une seconde,
 | |
|       puis en lancer deux, attendre une seconde, puis en lancer quatre et
 | |
|       ainsi de suite jusqu'à lancer 32 processus. Il s'arrêtera lorsque le
 | |
|       nombre de processus aura atteint la valeur définie par la directive
 | |
|       <directive module="prefork">MinSpareServers</directive>.</p>
 | |
| 
 | |
|       <p>Ceci s'avère suffisamment réactif pour pouvoir en général se passer
 | |
|       de manipuler les valeurs des directives
 | |
|       <directive module="prefork">MinSpareServers</directive>,
 | |
|       <directive module="prefork">MaxSpareServers</directive> et
 | |
|       <directive module="mpm_common">StartServers</directive>. Lorsque plus de
 | |
|       4 processus enfants sont lancés par seconde, un message est émis vers
 | |
|       le journal des erreurs. Si vous voyez apparaître souvent ce genre de
 | |
|       message, vous devez vous pencher sur ces réglages. Pour vous guider,
 | |
|       utilisez les informations délivrées par le module
 | |
|       <module>mod_status</module>.</p>
 | |
| 
 | |
|     <p>À mettre en relation avec la création de processus, leur destruction
 | |
|     est définie par la valeur de la directive
 | |
|     <directive module="mpm_common">MaxConnectionsPerChild</directive>. Sa valeur
 | |
|     par défaut est <code>0</code>, ce qui signifie qu'il n'y a pas de limite
 | |
|     au nombre de connexions qu'un processus enfant peut traiter. Si votre
 | |
|     configuration actuelle a cette directive réglée à une valeur très basse,
 | |
|     de l'ordre de <code>30</code>, il est conseillé de l'augmenter de manière
 | |
|     significative. Si vous utilisez SunOs ou une ancienne version de Solaris,
 | |
|     utilisez une valeur de l'ordre de <code>10000</code>  à cause des fuites
 | |
|     de mémoire.</p>
 | |
| 
 | |
|     <p>Lorsqu'ils sont en mode "keep-alive", les processus enfants sont
 | |
|     maintenus et ne font rien sinon attendre la prochaine requête sur la
 | |
|     connexion déjà ouverte. La valeur par défaut de <code>5</code> de la
 | |
|     directive <directive module="core">KeepAliveTimeout</directive> tend à
 | |
|     minimiser cet effet. Il faut trouver le bon compromis entre la bande
 | |
|     passante réseau et les ressources du serveur. En aucun cas vous ne devez
 | |
|     choisir une valeur supérieure à <code>60</code> seconds, car
 | |
|     <a href="http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-4.html">
 | |
|     la plupart des bénéfices sont alors perdus</a>.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|   </section>
 | |
| 
 | |
|   <section id="compiletime">
 | |
| 
 | |
|     <title>Optimisation de la configuration à la compilation</title>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Choisir un Module Multi-Processus (MPM)</title>
 | |
| 
 | |
|       <p>Apache 2.x supporte les modèles simultanés enfichables, appelés
 | |
|       <a href="../mpm.html">Modules Multi-Processus</a> (MPMs). Vous devez
 | |
|       choisir un MPM au moment de la construction d'Apache. Certaines
 | |
|       plateformes ont des modules MPM spécifiques :
 | |
|       <module>mpm_netware</module>, <module>mpmt_os2</module> et
 | |
|       <module>mpm_winnt</module>. Sur les systèmes de type Unix, vous avez le
 | |
|       choix entre un grand nombre de modules MPM. Le choix du MPM peut affecter
 | |
|       la vitesse et l'évolutivité du démon httpd :</p>
 | |
| 
 | |
|       <ul>
 | |
| 
 | |
|         <li>Le MPM <module>worker</module> utilise plusieurs processus
 | |
| 	enfants possédant chacun de nombreux threads. Chaque thread gère une
 | |
| 	seule connexion à la fois. Worker est en général un bon choix pour les
 | |
| 	serveurs présentant un traffic important car il possède une empreinte
 | |
| 	mémoire plus petite que le MPM prefork.</li>
 | |
| 
 | |
| 	<li>Comme le MPM Worker, le MPM <module>event</module> utilise
 | |
| 	les threads, mais il a été conçu pour traiter davantage de
 | |
| 	requêtes simultanément en confiant une partie du travail à des
 | |
| 	threads de support, ce qui permet aux threads principaux de
 | |
| 	traiter de nouvelles requêtes.</li>
 | |
| 
 | |
|         <li>Le MPM <module>prefork</module> utilise plusieurs processus enfants
 | |
| 	possédant chacun un seul thread. Chaque processus gère une seule
 | |
| 	connexion à la fois. Sur de nombreux systèmes, prefork est comparable
 | |
| 	en matière de vitesse à worker, mais il utilise plus de mémoire. De par
 | |
| 	sa conception sans thread, prefork présente des avantages par rapport à
 | |
| 	worker dans certaines situations : il peut être utilisé avec les
 | |
| 	modules tiers qui ne supportent pas le threading, et son débogage est plus
 | |
| 	aisé sur les platesformes présentant un support du débogage des threads
 | |
| 	rudimentaire.</li>
 | |
| 
 | |
|       </ul>
 | |
| 
 | |
|       <p>Pour plus d'informations sur ces deux MPMs et les autres, veuillez
 | |
|       vous référer à la <a href="../mpm.html">documentation sur les
 | |
|       MPM</a>.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section id="modules">
 | |
| 
 | |
|         <title>Modules</title>
 | |
| 
 | |
|         <p>Comme le contrôle de l'utilisation de la mémoire est très important
 | |
| 	en matière de performance, il est conseillé d'éliminer les modules que
 | |
| 	vous n'utilisez pas vraiment. Si vous avez construit ces modules en
 | |
| 	tant que <a href="../dso.html">DSOs</a>, leur élimination consiste
 | |
| 	simplement à commenter la directive
 | |
| 	<directive module="mod_so">LoadModule</directive> associée à ce
 | |
| 	module. Ceci vous permet de vérifier si votre site fonctionne toujours
 | |
| 	après la suppression de tel ou tel module.</p>
 | |
| 
 | |
|         <p>Par contre, si les modules que vous voulez supprimer sont liés
 | |
| 	statiquement à votre binaire Apache, vous devrez recompiler ce dernier
 | |
| 	afin de pouvoir les éliminer.</p>
 | |
| 
 | |
|         <p>La question qui découle de ce qui précède est évidemment de
 | |
| 	savoir de quels modules vous avez besoin et desquels vous pouvez vous
 | |
| 	passer. La réponse sera bien entendu différente d'un site web à
 | |
| 	l'autre. Cependant, la liste <em>minimale</em> de modules nécessaire à
 | |
| 	la survie de votre site contiendra certainement
 | |
| 	<module>mod_mime</module>, <module>mod_dir</module> et
 | |
| 	<module>mod_log_config</module>. <code>mod_log_config</code> est bien
 | |
| 	entendu optionnel puisque vous pouvez faire fonctionner un site web
 | |
| 	en se passant de fichiers journaux ; ceci est cependant
 | |
| 	déconseillé.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Opérations atomiques</title>
 | |
| 
 | |
|       <p>Certains modules, à l'instar de <module>mod_cache</module> et des
 | |
|       versions de développement récentes du MPM worker, utilisent l'API
 | |
|       atomique d'APR. Cette API propose des opérations atomiques que l'on
 | |
|       peut utiliser pour alléger la synchronisation des threads.</p>
 | |
| 
 | |
|       <p>Par défaut, APR implémente ces opérations en utilisant les
 | |
|       mécanismes les plus efficaces disponibles sur chaque plateforme cible
 | |
|       (Système d'exploitation et processeur). De nombreux processeurs modernes,
 | |
|       par exemple, possèdent une instruction qui effectue une opération
 | |
|       atomique de type comparaison et échange ou compare-and-swap (CAS) au
 | |
|       niveau matériel. Sur certaines platesformes cependant, APR utilise par
 | |
|       défaut une implémentation de l'API atomique plus lente, basée sur les
 | |
|       mutex, afin d'assurer la compatibilité avec les anciens modèles de
 | |
|       processeurs qui ne possèdent pas ce genre d'instruction. Si vous
 | |
|       construisez Apache pour une de ces platesformes, et ne prévoyez de
 | |
|       l'exécuter que sur des processeurs récents, vous pouvez sélectionner une
 | |
|       implémentation atomique plus rapide à la compilation en utilisant
 | |
|       l'option <code>--enable-nonportable-atomics</code> du
 | |
|       script configure :</p>
 | |
| 
 | |
|       <example>
 | |
|         ./buildconf<br />
 | |
|         ./configure --with-mpm=worker --enable-nonportable-atomics=yes
 | |
|       </example>
 | |
| 
 | |
|       <p>L'option <code>--enable-nonportable-atomics</code> concerne les
 | |
|       platesformes suivantes :</p>
 | |
| 
 | |
|       <ul>
 | |
| 
 | |
|         <li>Solaris sur SPARC<br />
 | |
|             Sur Solaris/SPARC, APR utilise par défaut les opérations
 | |
| 	    atomiques basées sur les mutex. Cependant, si vous ajoutez l'option
 | |
| 	    <code>--enable-nonportable-atomics</code> au script configure, APR
 | |
| 	    génère un code qui utilise le code opération SPARC v8plus pour des
 | |
| 	    opérations de compare-and-swap matériel plus rapides. Si vous
 | |
| 	    utilisez cette option de configure avec Apache, les opérations
 | |
| 	    atomiques seront plus efficaces (permettant d'alléger la charge du
 | |
| 	    processeur et un plus haut niveau de simultanéité), mais
 | |
| 	    l'exécutable produit ne fonctionnera que sur les processeurs
 | |
| 	    UltraSPARC.
 | |
| 	</li>
 | |
| 
 | |
|         <li>Linux sur x86<br />
 | |
|             Sous Linux, APR utilise par défaut les opérations atomiques basées
 | |
| 	    sur les mutex. Cependant, si vous ajoutez l'option
 | |
| 	    <code>--enable-nonportable-atomics</code> au script configure,
 | |
| 	    APR générera un code qui utilise un code d'opération du 486
 | |
| 	    pour des opérations de compare-and-swap matériel plus rapides. Le
 | |
| 	    code résultant est plus efficace en matière d'opérations atomiques,
 | |
| 	    mais l'exécutable produit ne fonctionnera que sur des processeurs
 | |
| 	    486 et supérieurs (et non sur des 386).
 | |
|         </li>
 | |
| 
 | |
|       </ul>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Module mod_status et ExtendedStatus On</title>
 | |
| 
 | |
|       <p>Si vous incluez le module <module>mod_status</module> à la
 | |
|       construction d'Apache et ajoutez <code>ExtendedStatus On</code> à sa
 | |
|       configuration, Apache va effectuer pour chaque requête deux appels à
 | |
|       <code>gettimeofday(2)</code> (ou <code>times(2)</code> selon votre
 | |
|       système d'exploitation), et (pour les versions antérieures à 1.3) de
 | |
|       nombreux appels supplémentaires à <code>time(2)</code>. Tous ces
 | |
|       appels sont effectués afin que le rapport de statut puisse contenir
 | |
|       des indications temporelles. Pour améliorer les performances, utilisez
 | |
|       <code>ExtendedStatus off</code> (qui est le réglage par défaut).</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>accept Serialization - points de connexion à un programme (sockets) multiples</title>
 | |
| 
 | |
|     <note type="warning"><title>Mise en garde :</title>
 | |
|       <p>Cette section n'a pas été totalement mise à jour car elle ne tient pas
 | |
|       compte des changements intervenus dans la version 2.x du Serveur HTTP
 | |
|       Apache. Certaines informations sont encore pertinentes, il vous est
 | |
|       cependant conseillé de les utiliser avec prudence.</p>
 | |
|     </note>
 | |
| 
 | |
|       <p>Ce qui suit est une brève discussion à propos de l'API des sockets
 | |
|       Unix. Supposons que votre serveur web utilise plusieurs directives
 | |
|       <directive module="mpm_common">Listen</directive> afin d'écouter
 | |
|       plusieurs ports ou de multiples adresses. Afin de tester chaque socket
 | |
|       pour voir s'il a une connexion en attente, Apache utilise
 | |
|       <code>select(2)</code>. <code>select(2)</code> indique si un socket a
 | |
|       <em>zéro</em> ou <em>au moins une</em> connexion en attente. Le modèle
 | |
|       d'Apache comporte plusieurs processus enfants, et tous ceux qui sont
 | |
|       inactifs testent la présence de nouvelles connexions au même moment.
 | |
|       Une implémentation rudimentaire de ceci pourrait ressembler à
 | |
|       l'exemple suivant
 | |
|       (ces exemples ne sont pas extraits du code d'Apache, ils ne sont
 | |
|       proposés qu'à des fins pédagogiques) :</p>
 | |
| 
 | |
|       <highlight language="c">
 | |
|         for (;;) {
 | |
|           for (;;) {
 | |
|             fd_set accept_fds;
 | |
| 
 | |
|             FD_ZERO (&accept_fds);
 | |
|             for (i = first_socket; i <= last_socket; ++i) {
 | |
|               FD_SET (i, &accept_fds);
 | |
|             }
 | |
|             rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
 | |
|             if (rc < 1) continue;
 | |
|             new_connection = -1;
 | |
|             for (i = first_socket; i <= last_socket; ++i) {
 | |
|               if (FD_ISSET (i, &accept_fds)) {
 | |
|                 new_connection = accept (i, NULL, NULL);
 | |
|                 if (new_connection != -1) break;
 | |
|               }
 | |
|             }
 | |
|             if (new_connection != -1) break;
 | |
|           }
 | |
|           process_the(new_connection);
 | |
|         }
 | |
|       </highlight>
 | |
| 
 | |
|       <p>Mais cette implémentation rudimentaire présente une sérieuse lacune.
 | |
|       Rappelez-vous que les processus enfants exécutent cette boucle au même
 | |
|       moment ; ils vont ainsi bloquer sur <code>select</code> s'ils se trouvent
 | |
|       entre deux requêtes. Tous ces processus bloqués vont se réactiver et
 | |
|       sortir de <code>select</code> quand une requête va apparaître sur un des
 | |
|       sockets (le nombre de processus enfants qui se réactivent varie en
 | |
|       fonction du système d'exploitation et des réglages de synchronisation).
 | |
|       Ils vont alors tous entrer dans la boucle et tenter un
 | |
|       <code>"accept"</code> de la connexion. Mais seulement un d'entre eux y
 | |
|       parviendra (en supposant qu'il ne reste q'une seule connexion en
 | |
|       attente), les autres vont se bloquer au niveau de <code>accept</code>.
 | |
|       Ceci verrouille vraiment ces processus de telle sorte qu'ils ne peuvent
 | |
|       plus servir de requêtes que par cet unique socket, et il en sera ainsi
 | |
|       jusqu'à ce que suffisamment de nouvelles requêtes apparaissent sur ce
 | |
|       socket pour les réactiver tous. Cette lacune a été documentée pour la
 | |
|       première fois dans
 | |
|       <a href="http://bugs.apache.org/index/full/467">PR#467</a>. Il existe
 | |
|       au moins deux solutions.</p>
 | |
| 
 | |
|       <p>La première consiste à rendre les sockets non blocants. Dans ce cas,
 | |
|       <code>accept</code> ne bloquera pas les processus enfants, et ils
 | |
|       pourront continuer à s'exécuter immédiatement. Mais ceci consomme des
 | |
|       ressources processeur. Supposons que vous ayez dix processus enfants
 | |
|       inactifs dans <code>select</code>, et qu'une connexion arrive.
 | |
|       Neuf des dix processus vont se réactiver, tenter un <code>accept</code>
 | |
|       de la connexion, échouer, et boucler dans <code>select</code>, tout en
 | |
|       n'ayant finalement rien accompli. Pendant ce temps, aucun de ces processus
 | |
|       ne traite les requêtes qui arrivent sur d'autres sockets jusqu'à ce
 | |
|       qu'ils retournent dans <code>select</code>. Finalement, cette solution
 | |
|       ne semble pas très efficace, à moins que vous ne disposiez d'autant de
 | |
|       processeurs inactifs (dans un serveur multiprocesseur) que de processus
 | |
|       enfants inactifs, ce qui n'est pas une situation très courante.</p>
 | |
| 
 | |
|       <p>Une autre solution, celle qu'utilise Apache, consiste à sérialiser les
 | |
|       entrées dans la boucle interne. La boucle ressemble à ceci (les
 | |
|       différences sont mises en surbrillance) :</p>
 | |
| 
 | |
|       <highlight language="c">
 | |
|         for (;;) {
 | |
|           <strong>accept_mutex_on ();</strong>
 | |
|           for (;;) {
 | |
|             fd_set accept_fds;
 | |
|             
 | |
|             FD_ZERO (&accept_fds);
 | |
|             for (i = first_socket; i <= last_socket; ++i) {
 | |
|               FD_SET (i, &accept_fds);
 | |
|             }
 | |
|             rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
 | |
|             if (rc < 1) continue;
 | |
|             new_connection = -1;
 | |
|             for (i = first_socket; i <= last_socket; ++i) {
 | |
|               if (FD_ISSET (i, &accept_fds)) {
 | |
|                 new_connection = accept (i, NULL, NULL);
 | |
|                 if (new_connection != -1) break;
 | |
|               }
 | |
|             }
 | |
|             if (new_connection != -1) break;
 | |
|           }
 | |
|           <strong>accept_mutex_off ();</strong>
 | |
|           process the new_connection;
 | |
|         }
 | |
|       </highlight>
 | |
| 
 | |
|       <p><a id="serialize" name="serialize">Les fonctions</a>
 | |
|       <code>accept_mutex_on</code> et <code>accept_mutex_off</code>
 | |
|       implémentent un sémaphore permettant une exclusion mutuelle. Un seul
 | |
|       processus enfant à la fois peut posséder le mutex. Plusieurs choix se
 | |
|       présentent pour implémenter ces mutex. Ce choix est défini dans
 | |
|       <code>src/conf.h</code> (versions antérieures à 1.3) ou
 | |
|       <code>src/include/ap_config.h</code> (versions 1.3 ou supérieures).
 | |
|       Certaines architectures ne font pas ce choix du mode de verrouillage ;
 | |
|       l'utilisation de directives
 | |
|       <directive module="mpm_common">Listen</directive> multiples sur ces
 | |
|       architectures est donc peu sûr.</p>
 | |
| 
 | |
|       <p>La directive <directive module="core">Mutex</directive> permet
 | |
|       de modifier l'implémentation du mutex <code>mpm-accept</code> à
 | |
|       l'exécution. Des considérations spécifiques aux différentes
 | |
|       implémentations de mutex sont documentées avec cette directive.</p>
 | |
| 
 | |
|       <p>Une autre solution qui a été imaginée mais jamais implémentée, consiste
 | |
|       à sérialiser partiellement la boucle -- c'est à dire y faire entrer un
 | |
|       certain nombre de processus. Ceci ne présenterait un intérêt que sur les
 | |
|       machines multiprocesseurs où plusieurs processus enfants peuvent
 | |
|       s'exécuter simultanément, et encore, la sérialisation ne tire pas
 | |
|       vraiment parti de toute la bande passante. C'est une possibilité
 | |
|       d'investigation future, mais demeure de priorité basse car les serveurs
 | |
|       web à architecture hautement parallèle ne sont pas la norme.</p>
 | |
| 
 | |
|       <p>Pour bien faire, vous devriez faire fonctionner votre serveur sans
 | |
|       directives <directive module="mpm_common">Listen</directive> multiples
 | |
|       si vous visez les performances les plus élevées.
 | |
|       Mais lisez ce qui suit.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>accept Serialization - point de connexion à un programme (sockets) unique</title>
 | |
| 
 | |
|       <p>Ce qui précède convient pour les serveurs à sockets multiples, mais
 | |
|       qu'en est-il des serveurs à socket unique ? En théorie, ils ne
 | |
|       devraient pas rencontrer les mêmes problèmes car tous les processus
 | |
|       enfants peuvent se bloquer dans <code>accept(2)</code> jusqu'à ce qu'une
 | |
|       connexion arrive, et ils ne sont pas utilisés à ne rien faire. En
 | |
|       pratique, ceci dissimule un même comportement de bouclage
 | |
|       discuté plus haut dans la solution non-blocante. De la manière dont
 | |
|       sont implémentées les piles TCP, le noyau réactive véritablement tous les
 | |
|       processus bloqués dans <code>accept</code> quand une seule connexion
 | |
|       arrive. Un de ces processus prend la connexion en compte et retourne
 | |
|       dans l'espace utilisateur, les autres bouclant dans l'espace du
 | |
|       noyau et se désactivant quand ils s'aperçoivent qu'il n'y a pas de
 | |
|       connexion pour eux. Ce bouclage est invisible depuis le code de l'espace
 | |
|       utilisateur, mais il est quand-même présent. Ceci peut conduire à la
 | |
|       même augmentation de charge à perte que la solution non blocante au cas
 | |
|       des sockets multiples peut induire.</p>
 | |
| 
 | |
|       <p>Pour cette raison, il apparaît que de nombreuses architectures se
 | |
|       comportent plus "proprement" si on sérialise même dans le cas d'une socket
 | |
|       unique. Il s'agit en fait du comportement par défaut dans la plupart des
 | |
|       cas. Des expériences poussées sous Linux (noyau 2.0.30 sur un
 | |
|       biprocesseur Pentium pro 166 avec 128 Mo de RAM) ont montré que la
 | |
|       sérialisation d'une socket unique provoque une diminution inférieure à 3%
 | |
|       du nombre de requêtes par secondes par rapport au traitement non
 | |
|       sérialisé. Mais le traitement non sérialisé des sockets uniques induit
 | |
|       un temps de réponse supplémentaire de 100 ms pour chaque requête. Ce
 | |
|       temps de réponse est probablement provoqué par une limitation sur les
 | |
|       lignes à haute charge, et ne constitue un problème que sur les réseaux
 | |
|       locaux. Si vous voulez vous passer de la sérialisation des sockets
 | |
|       uniques, vous pouvez définir
 | |
|       <code>SINGLE_LISTEN_UNSERIALIZED_ACCEPT</code> et les
 | |
|       serveurs à socket unique ne pratiqueront plus du tout la
 | |
|       sérialisation.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Fermeture en prenant son temps (Lingering close)</title>
 | |
| 
 | |
|       <p>Comme discuté dans <a
 | |
|       href="http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt">
 | |
|       draft-ietf-http-connection-00.txt</a> section 8, pour implémenter de
 | |
|       manière <strong>fiable</strong> le protocole, un serveur HTTP doit fermer
 | |
|       les deux directions d'une communication indépendamment (rappelez-vous
 | |
|       qu'une connexion TCP est bidirectionnelle, chaque direction étant
 | |
|       indépendante de l'autre).</p>
 | |
| 
 | |
|       <p>Quand cette fonctionnalité fut ajoutée à Apache, elle causa une
 | |
|       avalanche de problèmes sur plusieurs versions d'Unix à cause d'une
 | |
|       implémentation à courte vue. La spécification TCP ne précise pas que
 | |
|       l'état <code>FIN_WAIT_2</code> possède un temps de réponse mais elle ne
 | |
|       l'exclut pas. Sur les systèmes qui n'introduisent pas ce temps de
 | |
|       réponse, Apache 1.2 induit de nombreux blocages définitifs de socket
 | |
|       dans l'état <code>FIN_WAIT_2</code>. On peut eviter ceci dans de nombreux
 | |
|       cas tout simplement en mettant à jour TCP/IP avec le dernier patch mis à
 | |
|       disposition par le fournisseur. Dans les cas où le fournisseur n'a
 | |
|       jamais fourni de patch (par exemple, SunOS4 -- bien que les utilisateurs
 | |
|       possédant une license source puissent le patcher eux-mêmes), nous avons
 | |
|       décidé de désactiver cette fonctionnalité.</p>
 | |
| 
 | |
|       <p>Il y a deux méthodes pour arriver à ce résultat. La première est
 | |
|       l'option de socket <code>SO_LINGER</code>. Mais le sort a voulu que cette
 | |
|       solution ne soit jamais implémentée correctement dans la plupart des
 | |
|       piles TCP/IP. Et même dans les rares cas où cette solution a été
 | |
|       implémentée correctement (par exemple Linux 2.0.31), elle se
 | |
|       montre beaucoup plus gourmande (en temps processeur) que la solution
 | |
|       suivante.</p>
 | |
| 
 | |
|       <p>Pour la plus grande partie, Apache implémente cette solution à l'aide
 | |
|       d'une fonction appelée <code>lingering_close</code> (définie dans
 | |
|       <code>http_main.c</code>). La fonction ressemble approximativement à
 | |
|       ceci :</p>
 | |
| 
 | |
|       <highlight language="c">
 | |
|         void lingering_close (int s)
 | |
|         {
 | |
|           char junk_buffer[2048];
 | |
|           
 | |
|           /* shutdown the sending side */
 | |
|           shutdown (s, 1);
 | |
| 
 | |
|           signal (SIGALRM, lingering_death);
 | |
|           alarm (30);
 | |
| 
 | |
|           for (;;) {
 | |
|             select (s for reading, 2 second timeout);
 | |
|             if (error) break;
 | |
|             if (s is ready for reading) {
 | |
|               if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {
 | |
|                 break;
 | |
|               }
 | |
|               /* just toss away whatever is here */
 | |
|             }
 | |
|           }
 | |
|           
 | |
|           close (s);
 | |
|         }
 | |
|       </highlight>
 | |
| 
 | |
|       <p>Ceci ajoute naturellement un peu de charge à la fin d'une connexion,
 | |
|       mais s'avère nécessaire pour une implémentation fiable. Comme HTTP/1.1
 | |
|       est de plus en plus présent et que toutes les connexions sont
 | |
|       persistentes, la charge sera amortie par la multiplicité des requêtes.
 | |
|       Si vous voulez jouer avec le feu en désactivant cette fonctionnalité,
 | |
|       vous pouvez définir <code>NO_LINGCLOSE</code>, mais c'est fortement
 | |
|       déconseillé. En particulier, comme les connexions persistantes en
 | |
|       pipeline de HTTP/1.1 commencent à être utilisées,
 | |
|       <code>lingering_close</code> devient une absolue nécessité (et les
 | |
|       <a
 | |
|       href="http://www.w3.org/Protocols/HTTP/Performance/Pipeline.html">
 | |
|       connexions en pipeline sont plus rapides</a> ; vous avez donc tout
 | |
|       intérêt à les supporter).</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>Fichier tableau de bord (Scoreboard file)</title>
 | |
| 
 | |
|       <p>Les processus parent et enfants d'Apache communiquent entre eux à
 | |
|       l'aide d'un objet appelé "Tableau de bord" (Scoreboard). Idéalement, cet
 | |
|       échange devrait s'effectuer en mémoire partagée. Pour les systèmes
 | |
|       d'exploitation auxquels nous avons eu accès, ou pour lesquels nous avons
 | |
|       obtenu des informations suffisamment détaillées pour effectuer un
 | |
|       portage, cet échange est en général implémenté en utilisant la mémoire
 | |
|       partagée. Pour les autres, on utilise par défaut un fichier d'échange sur
 | |
|       disque. Le fichier d'échange sur disque est non seulement lent, mais
 | |
|       aussi peu fiable (et propose moins de fonctionnalités). Recherchez dans
 | |
|       le fichier <code>src/main/conf.h</code> correspondant à votre
 | |
|       architecture soit <code>USE_MMAP_SCOREBOARD</code>, soit
 | |
|       <code>USE_SHMGET_SCOREBOARD</code>. La définition de l'un des deux
 | |
|       (ainsi que leurs compagnons respectifs <code>HAVE_MMAP</code> et
 | |
|       <code>HAVE_SHMGET</code>), active le code fourni pour la mémoire
 | |
|       partagée. Si votre système propose une autre solution pour la gestion de
 | |
|       la mémoire partagée, éditez le fichier <code>src/main/http_main.c</code>
 | |
|       et ajoutez la portion de code nécessaire pour pouvoir l'utiliser dans
 | |
|       Apache (Merci de nous envoyer aussi le patch correspondant).</p>
 | |
| 
 | |
|       <note>Note à caractère historique : le portage d'Apache sous Linux
 | |
|       n'utilisait pas la mémoire partagée avant la version 1.2. Ceci entraînait
 | |
|       un comportement très rudimentaire et peu fiable des versions antérieures
 | |
|       d'Apache sous Linux.</note>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|     <section>
 | |
| 
 | |
|       <title>DYNAMIC_MODULE_LIMIT</title>
 | |
| 
 | |
|       <p>Si vous n'avez pas l'intention d'utiliser les modules chargés
 | |
|       dynamiquement (ce qui est probablement le cas si vous êtes en train de
 | |
|       lire ce document afin de personnaliser votre serveur en recherchant le
 | |
|       moindre des gains en performances), vous pouvez ajouter la définition
 | |
|       <code>-DDYNAMIC_MODULE_LIMIT=0</code> à la construction de votre serveur.
 | |
|       Ceci aura pour effet de libérer la mémoire RAM allouée pour le
 | |
|       chargement dynamique des modules.</p>
 | |
| 
 | |
|     </section>
 | |
| 
 | |
|   </section>
 | |
| 
 | |
|   <section id="trace">
 | |
| 
 | |
|     <title>Appendice : Analyse détaillée d'une trace</title>
 | |
| 
 | |
|     <p>Voici la trace d'un appel système d'Apache 2.0.38 avec le MPM worker
 | |
|     sous Solaris 8. Cette trace a été collectée à l'aide de la commande :</p>
 | |
| 
 | |
|     <example>
 | |
|       truss -l -p <var>httpd_child_pid</var>.
 | |
|     </example>
 | |
| 
 | |
|     <p>L'option <code>-l</code> demande à truss de tracer l'ID du LWP
 | |
|     (lightweight process--la version de Solaris des threads niveau noyau) qui
 | |
|     invoque chaque appel système.</p>
 | |
| 
 | |
|     <p>Les autres systèmes peuvent proposer des utilitaires de traçage
 | |
|     des appels système différents comme <code>strace</code>,
 | |
|     <code>ktrace</code>, ou <code>par</code>. Ils produisent cependant tous une
 | |
|     trace similaire.</p>
 | |
| 
 | |
|     <p>Dans cette trace, un client a demandé un fichier statique de 10 ko au
 | |
|     démon httpd. Le traçage des requêtes pour des contenus non statiques
 | |
|     ou comportant une négociation de contenu a une présentation
 | |
|     différente (et même assez laide dans certains cas).</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/67:    accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
 | |
| /67:    accept(3, 0x00200BEC, 0x00200C0C, 1)            = 9</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Dans cette trace, le thread à l'écoute s'exécute à l'intérieur de
 | |
|     LWP #67.</p>
 | |
| 
 | |
|     <note>Notez l'absence de la sérialisation d'<code>accept(2)</code>. Sur
 | |
|     cette plateforme spécifique, le MPM worker utilise un accept non sérialisé
 | |
|     par défaut sauf s'il est en écoute sur des ports multiples.</note>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    lwp_park(0x00000000, 0)                         = 0
 | |
| /67:    lwp_unpark(65, 1)                               = 0</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Après avoir accepté la connexion, le thread à l'écoute réactive un
 | |
|     thread du worker pour effectuer le traitement de la requête. Dans cette
 | |
|     trace, le thread du worker qui traite la requête est associé à
 | |
|     LWP #65.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Afin de pouvoir implémenter les hôtes virtuels, Apache doit connaître
 | |
|     l'adresse du socket local utilisé pour accepter la connexion. On pourrait
 | |
|     supprimer cet appel dans de nombreuses situations (par exemple dans le cas
 | |
|     où il n'y a pas d'hôte virtuel ou dans le cas où les directives
 | |
|     <directive module="mpm_common">Listen</directive> contiennent des adresses
 | |
|     sans caractères de substitution). Mais aucun effort n'a été accompli à ce
 | |
|     jour pour effectuer ces optimisations.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    brk(0x002170E8)                                 = 0
 | |
| /65:    brk(0x002190E8)                                 = 0</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>L'appel <code>brk(2)</code> alloue de la mémoire dans le tas. Ceci est
 | |
|     rarement visible dans une trace d'appel système, car le démon httpd
 | |
|     utilise des allocateurs mémoire de son cru (<code>apr_pool</code> et
 | |
|     <code>apr_bucket_alloc</code>) pour la plupart des traitements de requêtes.
 | |
|     Dans cette trace, le démon httpd vient juste de démarrer, et il doit
 | |
|     appeler <code>malloc(3)</code> pour réserver les blocs de mémoire
 | |
|     nécessaires à la création de ses propres allocateurs de mémoire.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    fcntl(9, F_GETFL, 0x00000000)                   = 2
 | |
| /65:    fstat64(9, 0xFAF7B818)                          = 0
 | |
| /65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
 | |
| /65:    fstat64(9, 0xFAF7B818)                          = 0
 | |
| /65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
 | |
| /65:    setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
 | |
| /65:    fcntl(9, F_SETFL, 0x00000082)                   = 0</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Ensuite, le thread de worker passe la connexion du client (descripteur
 | |
|     de fichier 9) en mode non blocant. Les appels <code>setsockopt(2)</code>
 | |
|     et <code>getsockopt(2)</code> constituent un effet de bord de la manière
 | |
|     dont la libc de Solaris utilise <code>fcntl(2)</code> pour les sockets.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    read(9, " G E T   / 1 0 k . h t m".., 8000)     = 97</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Le thread de worker lit la requête du client.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
 | |
| /65:    open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Ce démon httpd a été configuré avec les options
 | |
|     <code>Options FollowSymLinks</code> et <code>AllowOverride None</code>. Il
 | |
|     n'a donc ni besoin d'appeler <code>lstat(2)</code> pour chaque répertoire
 | |
|     du chemin du fichier demandé, ni besoin de vérifier la présence de fichiers
 | |
|     <code>.htaccess</code>. Il appelle simplement <code>stat(2)</code> pour
 | |
|     vérifier d'une part que le fichier existe, et d'autre part que c'est un
 | |
|     fichier régulier, et non un répertoire.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Dans cet exemple, le démon httpd peut envoyer l'en-tête de la réponse
 | |
|     HTTP et le fichier demandé à l'aide d'un seul appel système
 | |
|     <code>sendfilev(2)</code>. La sémantique de sendfile varie en fonction des
 | |
|     systèmes d'exploitation. Sur certains autres systèmes, il faut faire un
 | |
|     appel à <code>write(2)</code> ou <code>writev(2)</code> pour envoyer les
 | |
|     en-têtes avant d'appeler <code>sendfile(2)</code>.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    write(4, " 1 2 7 . 0 . 0 . 1   -  ".., 78)      = 78</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Cet appel à <code>write(2)</code> enregistre la requête dans le journal
 | |
|     des accès. Notez qu'une des choses manquant à cette trace est un appel à
 | |
|     <code>time(2)</code>. A la différence d'Apache 1.3, Apache 2.x utilise
 | |
|     <code>gettimeofday(3)</code> pour consulter l'heure. Sur certains systèmes
 | |
|     d'exploitation, comme Linux ou Solaris, <code>gettimeofday</code> est
 | |
|     implémenté de manière optimisée de telle sorte qu'il consomme moins de
 | |
|     ressources qu'un appel système habituel.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    shutdown(9, 1, 1)                               = 0
 | |
| /65:    poll(0xFAF7B980, 1, 2000)                       = 1
 | |
| /65:    read(9, 0xFAF7BC20, 512)                        = 0
 | |
| /65:    close(9)                                        = 0</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Le thread de worker effectue une fermeture "en prenant son temps"
 | |
|     (lingering close) de la connexion.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/65:    close(10)                                       = 0
 | |
| /65:    lwp_park(0x00000000, 0)         (sleeping...)</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Enfin, le thread de worker ferme le fichier qu'il vient de délivrer et
 | |
|     se bloque jusqu'à ce que le thread en écoute lui assigne une autre
 | |
|     connexion.</p>
 | |
| 
 | |
|     <example>
 | |
| <pre>/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)</pre>
 | |
|     </example>
 | |
| 
 | |
|     <p>Pendant ce temps, le thread à l'écoute peut accepter une autre connexion
 | |
|     à partir du moment où il a assigné la connexion présente à un thread de
 | |
|     worker (selon une certaine logique de contrôle de flux dans le MPM worker
 | |
|     qui impose des limites au thread à l'écoute si tous les threads de worker
 | |
|     sont occupés). Bien que cela n'apparaisse pas dans cette trace,
 | |
|     l'<code>accept(2)</code> suivant peut (et le fait en général, en situation
 | |
|     de charge élevée) s'exécuter en parallèle avec le traitement de la
 | |
|     connexion qui vient d'être acceptée par le thread de worker.</p>
 | |
| 
 | |
|   </section>
 | |
| 
 | |
| </manualpage>
 | |
| 
 |