diff options
author | Vincent Deffontaines <gryzor@apache.org> | 2009-02-08 12:21:21 +0100 |
---|---|---|
committer | Vincent Deffontaines <gryzor@apache.org> | 2009-02-08 12:21:21 +0100 |
commit | 2cb161dafc735c7b8d133c5080a82a1880dceb20 (patch) | |
tree | 69518d79c2adb2084ef5ca490711548b477c567d /docs/manual/misc/perf-tuning.xml.fr | |
parent | New french translation for the SSI howto (diff) | |
download | apache2-2cb161dafc735c7b8d133c5080a82a1880dceb20.tar.xz apache2-2cb161dafc735c7b8d133c5080a82a1880dceb20.zip |
New french translations.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@742058 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'docs/manual/misc/perf-tuning.xml.fr')
-rw-r--r-- | docs/manual/misc/perf-tuning.xml.fr | 1174 |
1 files changed, 1174 insertions, 0 deletions
diff --git a/docs/manual/misc/perf-tuning.xml.fr b/docs/manual/misc/perf-tuning.xml.fr new file mode 100644 index 0000000000..4c962f5c1e --- /dev/null +++ b/docs/manual/misc/perf-tuning.xml.fr @@ -0,0 +1,1174 @@ +<?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 : 740028 --> +<!-- 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">MaxClients</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> + + <example> + HostnameLookups off<br /> + <Files ~ "\.(html|cgi)$"><br /> + <indent> + HostnameLookups on<br /> + </indent> + </Files> + </example> + + <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> + + <example> + DocumentRoot /www/htdocs<br /> + <Directory /><br /> + <indent> + Options SymLinksIfOwnerMatch<br /> + </indent> + </Directory> + </example> + + <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> + + <example> + DocumentRoot /www/htdocs<br /> + <Directory /><br /> + <indent> + Options FollowSymLinks<br /> + </indent> + </Directory><br /> + <br /> + <Directory /www/htdocs><br /> + <indent> + Options -FollowSymLinks +SymLinksIfOwnerMatch<br /> + </indent> + </Directory> + </example> + + <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="htacess"> + + <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> + + <example> + DocumentRoot /www/htdocs<br /> + <Directory /><br /> + <indent> + AllowOverride all<br /> + </indent> + </Directory> + </example> + + <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> + + <example> + DirectoryIndex index + </example> + + <p>utilisez une liste explicite d'options :</p> + + <example> + DirectoryIndex index.cgi index.pl index.shtml index.html + </example> + + <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 des fichiers montés 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">MaxRequestsPerChild</directive>. Sa valeur + par défaut est <code>0</code>, ce qui signifie qu'il n'y a pas de limite + au nombre de requêtes q'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.research.digital.com/wrl/techreports/abstracts/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>beos</module>, + <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>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> + + <example> + for (;;) {<br /> + <indent> + for (;;) {<br /> + <indent> + fd_set accept_fds;<br /> + <br /> + FD_ZERO (&accept_fds);<br /> + for (i = first_socket; i <= last_socket; ++i) {<br /> + <indent> + FD_SET (i, &accept_fds);<br /> + </indent> + }<br /> + rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br /> + if (rc < 1) continue;<br /> + new_connection = -1;<br /> + for (i = first_socket; i <= last_socket; ++i) {<br /> + <indent> + if (FD_ISSET (i, &accept_fds)) {<br /> + <indent> + new_connection = accept (i, NULL, NULL);<br /> + if (new_connection != -1) break;<br /> + </indent> + }<br /> + </indent> + }<br /> + if (new_connection != -1) break;<br /> + </indent> + }<br /> + process the new_connection;<br /> + </indent> + } + </example> + + <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> + + <example> + for (;;) {<br /> + <indent> + <strong>accept_mutex_on ();</strong><br /> + for (;;) {<br /> + <indent> + fd_set accept_fds;<br /> + <br /> + FD_ZERO (&accept_fds);<br /> + for (i = first_socket; i <= last_socket; ++i) {<br /> + <indent> + FD_SET (i, &accept_fds);<br /> + </indent> + }<br /> + rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);<br /> + if (rc < 1) continue;<br /> + new_connection = -1;<br /> + for (i = first_socket; i <= last_socket; ++i) {<br /> + <indent> + if (FD_ISSET (i, &accept_fds)) {<br /> + <indent> + new_connection = accept (i, NULL, NULL);<br /> + if (new_connection != -1) break;<br /> + </indent> + }<br /> + </indent> + }<br /> + if (new_connection != -1) break;<br /> + </indent> + }<br /> + <strong>accept_mutex_off ();</strong><br /> + process the new_connection;<br /> + </indent> + } + </example> + + <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>On peut utiliser la directive + <directive module="mpm_common">AcceptMutex</directive> pour modifier + l'implémentation du mutex sélectionnée à l'exécution.</p> + + <dl> + <dt><code>AcceptMutex flock</code></dt> + + <dd> + <p>Cette méthode utilise l'appel système <code>flock(2)</code> pour + créer un fichier verrou (dont la localisation est définie par la + directive <directive module="mpm_common">LockFile</directive>.</p> + </dd> + + <dt><code>AcceptMutex fcntl</code></dt> + + <dd> + <p>Cette méthode utilise l'appel système <code>fcntl(2)</code> pour + créer un fichier verrou ((dont la localisation est définie par la + directive <directive module="mpm_common">LockFile</directive>.</p> + </dd> + + <dt><code>AcceptMutex sysvsem</code></dt> + + <dd> + <p>(Versions 1.3 ou supérieures) Cette méthode utilise les sémaphores + style SysV pour implémenter les mutex. Malheureusement, les + sémaphores style SysV ont quelques effets de bord néfastes. L'un + d'entre eux est la possibilité pour Apache de s'arrêter sans + "faire le ménage" dans les sémaphores (voir la page de manuel de + <code>ipcs(8)</code>). Un autre effet de bord est introduit par + l'API des sémaphores qui permet à tout CGI s'exécutant sous le même + uid que le serveur web d'effectuer une attaque par déni de service + (c'est à dire <em>tous</em> les CGIs, à moins que vous n'utilisiez + un programme comme <program>suexec</program> ou + <code>cgiwrapper</code>). C'est pour cette raison que cette méthode + n'est utilisée sur aucune architecture sauf IRIX (où les deux + méthodes précédentes consomment des ressources de manière prohibitive + sur la plupart des machines IRIX).</p> + </dd> + + <dt><code>AcceptMutex pthread</code></dt> + + <dd> + <p>(versions 1.3 ou supérieures) Cette méthode utilise les mutex + POSIX et devrait fonctionner sur toute architecture implémentant + de manière complète la spécification concernant les threads POSIX ; + il semble cependant qu'elle ne fonctionne que sur Solaris (versions + 2.5 ou supérieures), et sous certaines configurations seulement. Si + vous tentez l'expérience, votre serveur risque de se bloquer et de ne + plus répondre à vos sollicitations. Par contre, les serveurs + n'hébergeant que du contenu statique devraient fonctionner + correctement.</p> + </dd> + + <dt><code>AcceptMutex posixsem</code></dt> + + <dd> + <p>(Versions 2.0 ou supérieures) Cette méthode utilise les sémaphores + POSIX. L'appartenance du sémaphore n'est pas récupérée quand un + thread du processus qui détient le mutex provoque une erreur de + segmentation, ce qui a pour effet de bloquer le serveur.</p> + </dd> + + </dl> + + <p>Si votre système propose une méthode de sérialisation différente de + celles de la liste ci-dessus, il pourrait être intéressant d'ajouter à + APR le code correspondant.</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). Ce fait, souvent ignoré par les autres + serveurs, est implémenté correctement dans Apache depuis la + version 1.2.</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> + + <example> + void lingering_close (int s)<br /> + {<br /> + <indent> + char junk_buffer[2048];<br /> + <br /> + /* shutdown the sending side */<br /> + shutdown (s, 1);<br /> + <br /> + signal (SIGALRM, lingering_death);<br /> + alarm (30);<br /> + <br /> + for (;;) {<br /> + <indent> + select (s for reading, 2 second timeout);<br /> + if (error) break;<br /> + if (s is ready for reading) {<br /> + <indent> + if (read (s, junk_buffer, sizeof (junk_buffer)) <= 0) {<br /> + <indent> + break;<br /> + </indent> + }<br /> + /* just toss away whatever is here */<br /> + </indent> + }<br /> + </indent> + }<br /> + <br /> + close (s);<br /> + </indent> + } + </example> + + <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> + |