<?xml version="1.0" ?>
<!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
<?xml-stylesheet type="text/xsl" href="../style/manual.fr.xsl"?>
<!-- English Revision: 1675524 -->
<!-- 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 &agrave; usage g&eacute;n&eacute;ral, con&ccedil;u dans un but
    d'&eacute;quilibre entre souplesse, portabilit&eacute; et performances. Bien que non
    con&ccedil;u dans le seul but d'&eacute;tablir une r&eacute;f&eacute;rence en la mati&egrave;re,
    Apache 2.x est capable de hautes performances dans de nombreuses situations
    du monde r&eacute;el.</p>

    <p>Compar&eacute;e &agrave; Apache 1.3, la version 2.x comporte de nombreuses
    optimisations suppl&eacute;mentaires permettant d'am&eacute;liorer le d&eacute;bit du serveur
    et sa personnalisation. La plupart de ces am&eacute;liorations sont activ&eacute;es par
    d&eacute;faut. Cependant, certains choix de configuration &agrave; la compilation et &agrave;
    l'ex&eacute;cution peuvent affecter les performances de mani&egrave;re significative. Ce
    document d&eacute;crit les options qu'un administrateur de serveur peut configurer
    pour am&eacute;liorer les performances d'une installation d'Apache 2.x. Certaines
    de ces options de configuration permettent au d&eacute;mon httpd de mieux tirer
    parti des possibilit&eacute;s du mat&eacute;riel et du syst&egrave;me d'exploitation, tandis
    que d'autres permettent &agrave; l'administrateur de privil&eacute;gier la vitesse
    par rapport aux fonctionnalit&eacute;s.</p>

  </summary>

  <section id="hardware">

    <title>Probl&egrave;mes mat&eacute;riels et relatifs au syst&egrave;me d'exploitation</title>

    <p>Le principal probl&egrave;me mat&eacute;riel qui affecte les performances du serveur
    web est la m&eacute;moire vive (RAM). Un serveur web ne devrait jamais avoir &agrave;
    utiliser le swap, car le swapping augmente le temps de r&eacute;ponse de chaque
    requ&ecirc;te au del&agrave; du point que les utilisateurs consid&egrave;rent comme
    "trop lent". Ceci incite les utilisateurs &agrave; cliquer sur "Stop", puis
    "Charger &agrave; nouveau", ce qui a pour effet d'augmenter encore la charge
    du serveur. Vous pouvez, et m&ecirc;me devez d&eacute;finir la valeur de la directive
    <directive module="mpm_common">MaxRequestWorkers</directive> de fa&ccedil;on &agrave; ce que
    votre serveur ne lance pas un nombre de processus enfants tel qu'il
    commence &agrave; faire du swapping. La m&eacute;thode pour y parvenir est
    simple : d&eacute;terminez la taille de votre processus Apache standard en
    consultant votre liste de processus &agrave; l'aide d'un outil tel que
    <code>top</code>, et divisez votre quantit&eacute; totale de m&eacute;moire disponible
    par cette taille, tout en gardant un espace suffisant
    pour les autres processus.</p>

    <p>Hormis ce r&eacute;glage relatif &agrave; la m&eacute;moire, le reste est trivial : le
    processeur, la carte r&eacute;seau et les disques doivent &ecirc;tre suffisamment
    rapides, o&ugrave; "suffisamment rapide" doit &ecirc;tre d&eacute;termin&eacute; par
    l'exp&eacute;rience.</p>

    <p>Le choix du syst&egrave;me d'exploitation d&eacute;pend principalement du
    contexte local. Voici cependant quelques conseils qui se sont
    g&eacute;n&eacute;ralement av&eacute;r&eacute;s utiles :</p>

    <ul>
      <li>
        <p>Ex&eacute;cutez la derni&egrave;re version stable et le niveau de patches le
	plus haut du syst&egrave;me d'exploitation que vous avez choisi. De nombreux
	&eacute;diteurs de syst&egrave;mes d'exploitation ont am&eacute;lior&eacute; de mani&egrave;re
	significative les performances de leurs piles TCP et de leurs
	biblioth&egrave;ques de thread ces derni&egrave;res ann&eacute;es.</p>
      </li>

      <li>
        <p>Si votre syst&egrave;me d'exploitation poss&egrave;de un appel syst&egrave;me
	<code>sendfile(2)</code>, assurez-vous d'avoir install&eacute; la version
	et/ou les patches n&eacute;cessaires &agrave; son activation. (Pour Linux, par
	exemple, cela se traduit par Linux 2.4 ou plus. Pour les versions
	anciennes de Solaris 8, vous pouvez &ecirc;tre amen&eacute; &agrave; appliquer un patch.)
	Sur les syst&egrave;mes o&ugrave; il est disponible, <code>sendfile</code> permet
	&agrave; Apache 2 de servir les contenus statiques plus rapidement, tout en
	induisant une charge CPU inf&eacute;rieure.</p>
      </li>
    </ul>

  </section>

  <section id="runtime">

    <title>Optimisation de la configuration &agrave; l'ex&eacute;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&eacute;rations &agrave; propos du DNS</title>

      <p>Avant Apache 1.3, la directive
      <directive module="core">HostnameLookups</directive> &eacute;tait positionn&eacute;e
      par d&eacute;faut &agrave; <code>On</code>. Ce r&eacute;glage augmente le temps de r&eacute;ponse de
      chaque requ&ecirc;te car il entra&icirc;ne une recherche DNS et le traitement de la
      requ&ecirc;te ne pourra pas &ecirc;tre achev&eacute; tant que cette recherche ne sera
      pas termin&eacute;e. Avec Apache 1.3, ce r&eacute;glage est d&eacute;fini par d&eacute;faut &agrave;
      <code>Off</code>. Si vous souhaitez que les adresses dans vos fichiers
      journaux soient r&eacute;solues en noms d'h&ocirc;tes, utilisez le programme
      <program>logresolve</program> fourni avec Apache, ou un des nombreux
      paquets g&eacute;n&eacute;rateurs de rapports sur les journaux disponibles.</p>

      <p>Il est recommand&eacute; d'effectuer ce genre de traitement a posteriori
      de vos fichiers journaux sur une autre machine que celle qui h&eacute;berge le
      serveur web en production, afin que cette activit&eacute; 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&ocirc;te ou un nom de domaine &agrave;
      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 &eacute;t&eacute; usurp&eacute;e). C'est pourquoi il est
      pr&eacute;f&eacute;rable, pour am&eacute;liorer les performances, d'utiliser des adresses IP
      plut&ocirc;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&eacute;e des directives, en les
      pla&ccedil;ant par exemple &agrave; l'int&eacute;rieur d'une section
      <code>&lt;Location "/server-status"&gt;</code>. Les recherches DNS ne
      seront alors effectu&eacute;es que pour les requ&ecirc;tes qui satisfont aux crit&egrave;res.
      Voici un exemple qui d&eacute;sactive les recherches DNS sauf pour les fichiers
      <code>.html</code> et <code>.cgi</code> :</p>

      <highlight language="config">
HostnameLookups off
&lt;Files ~ "\.(html|cgi)$"&gt;
  HostnameLookups on
&lt;/Files&gt;
      </highlight>

      <p>Mais m&ecirc;me dans ce cas, si vous n'avez besoin de noms DNS que dans
      certains CGIs, vous pouvez effectuer l'appel &agrave; <code>gethostbyname</code>
      dans les CGIs sp&eacute;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&eacute;sente dans votre espace d'adressage, Apache devra effectuer des
      appels syst&egrave;me suppl&eacute;mentaires pour v&eacute;rifier la pr&eacute;sence de liens
      symboliques. Un appel suppl&eacute;mentaire par &eacute;l&eacute;ment du chemin du fichier.
      Par exemple, si vous avez :</p>

      <highlight language="config">
DocumentRoot "/www/htdocs"
&lt;Directory "/"&gt;
  Options SymLinksIfOwnerMatch
&lt;/Directory&gt;
      </highlight>

      <p>et si une requ&ecirc;te demande l'URI <code>/index.html</code>, Apache
      effectuera un appel &agrave; <code>lstat(2)</code> pour
      <code>/www</code>, <code>/www/htdocs</code>, et
      <code>/www/htdocs/index.html</code>. Les r&eacute;sultats de ces appels &agrave;
      <code>lstat</code> ne sont jamais mis en cache, ils devront donc &ecirc;tre
      g&eacute;n&eacute;r&eacute;s &agrave; nouveau pour chaque nouvelle requ&ecirc;te. Si vous voulez absolument
      v&eacute;rifier la s&eacute;curit&eacute; des liens symboliques, vous pouvez utiliser une
      configuration du style :</p>

      <highlight language="config">
DocumentRoot "/www/htdocs"
&lt;Directory "/"&gt;
  Options FollowSymLinks
&lt;/Directory&gt;

&lt;Directory "/www/htdocs"&gt;
  Options -FollowSymLinks +SymLinksIfOwnerMatch
&lt;/Directory&gt;
      </highlight>

      <p>Ceci &eacute;vite au moins les v&eacute;rifications suppl&eacute;mentaires pour le chemin
      d&eacute;fini par <directive module="core">DocumentRoot</directive>. Notez que
      vous devrez ajouter des sections similaires si vous avez des chemins
      d&eacute;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&eacute;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&ugrave; vous autoriserez
      la surcharge de la configuration (en g&eacute;n&eacute;ral &agrave; l'aide de fichiers
      <code>.htaccess</code>), Apache va tenter d'ouvrir <code>.htaccess</code>
      pour chaque &eacute;l&eacute;ment du chemin du fichier demand&eacute;. Par exemple, si vous
      avez : </p>

      <highlight language="config">
DocumentRoot "/www/htdocs"
&lt;Directory "/"&gt;
  AllowOverride all
&lt;/Directory&gt;
      </highlight>

      <p>et qu'une requ&ecirc;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 &agrave;
      celles &eacute;voqu&eacute;es pr&eacute;c&eacute;demment pour <code>Options FollowSymLinks</code>.
      Pour am&eacute;liorer les performances, utilisez <code>AllowOverride None</code>
      pour tous les niveaux de votre espace d'adressage.</p>

    </section>

    <section id="negotiation">

      <title>N&eacute;gociation</title>

      <p>Dans la mesure du possible, &eacute;vitez toute n&eacute;gociation de contenu si
      vous tenez au moindre gain en performances. En pratique toutefois,
      les b&eacute;n&eacute;fices de la n&eacute;gociation l'emportent souvent sur la diminution
      des performances.
      Il y a cependant un cas dans lequel vous pouvez acc&eacute;l&eacute;rer le serveur.
      Au lieu d'utiliser une directive g&eacute;n&eacute;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&ugrave; vous placez le choix courant en premi&egrave;re position.</p>

      <p>Notez aussi que cr&eacute;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&eacute;cessaires peuvent &ecirc;tre simplement obtenues en lisant ce fichier, sans
      avoir &agrave; parcourir le r&eacute;pertoire &agrave; la recherche de types de fichiers.</p>

    <p>Par cons&eacute;quent, si la n&eacute;gociation de contenu est n&eacute;cessaire pour votre
    site, pr&eacute;f&eacute;rez les fichiers de <code>correspondances de type</code> aux
    directives <code>Options MultiViews</code> pour mener &agrave; bien cette
    n&eacute;gociation. Se r&eacute;f&eacute;rer au document sur la
    <a href="../content-negotiation.html">N&eacute;gociation de contenu</a> pour une
    description compl&egrave;te des m&eacute;thodes de n&eacute;gociation, et les instructions
    permettant de cr&eacute;er des fichiers de <code>correspondances de type</code>.</p>

    </section>

    <section>

      <title>Transfert en m&eacute;moire</title>

      <p>Dans les situations o&ugrave; Apache 2.x doit consulter le contenu d'un
      fichier en train d'&ecirc;tre servi - par exemple &agrave; l'occasion du traitement
      d'une inclusion c&ocirc;t&eacute; serveur - il transf&egrave;re en g&eacute;n&eacute;ral le fichier en
      m&eacute;moire si le syst&egrave;me d'exploitation supporte une forme quelconque
      de <code>mmap(2)</code>.</p>

      <p>Sur certains syst&egrave;mes, ce transfert en m&eacute;moire am&eacute;liore les
      performances. Dans certains cas, ce transfert peut toutefois les d&eacute;grader
      et m&ecirc;me diminuer la stabilit&eacute; du d&eacute;mon httpd :</p>

      <ul>
        <li>
          <p>Dans certains syst&egrave;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&eacute;s par le
	  serveur plus rapidement quand <code>mmap</code> est d&eacute;sactiv&eacute;.</p>
        </li>

        <li>
          <p>Si vous transf&eacute;rez en m&eacute;moire un fichier localis&eacute; dans un syst&egrave;me
	  de fichiers mont&eacute; 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&eacute;der au contenu du fichier en m&eacute;moire.</p>
        </li>
      </ul>

      <p>Pour les installations o&ugrave; une de ces situations peut se produire,
      vous devez utiliser <code>EnableMMAP off</code> afin de d&eacute;sactiver le
      transfert en m&eacute;moire des fichiers servis. (Note : il est possible de
      passer outre cette directive au niveau de chaque r&eacute;pertoire.)</p>

    </section>

    <section>

      <title>Sendfile</title>

      <p>Dans les cas o&ugrave; Apache peut se permettre d'ignorer le contenu du
      fichier &agrave; servir - par exemple, lorsqu'il sert un contenu de fichier
      statique - il utilise en g&eacute;n&eacute;ral le support sendfile du noyau si le
      syst&egrave;me d'exploitation supporte l'op&eacute;ration <code>sendfile(2)</code>.</p>

      <p>Sur la plupart des plateformes, l'utilisation de sendfile am&eacute;liore
      les performances en &eacute;liminant les m&eacute;canismes de lecture et envoi s&eacute;par&eacute;s.
      Dans certains cas cependant, l'utilisation de sendfile peut nuire &agrave; la
      stabilit&eacute; du d&eacute;mon httpd :</p>

      <ul>
        <li>
          <p>Certaines plateformes peuvent pr&eacute;senter un support de sendfile
	  d&eacute;faillant que la construction du syst&egrave;me n'a pas d&eacute;tect&eacute;, en
	  particulier si les binaires ont &eacute;t&eacute; construits sur une autre machine
	  et transf&eacute;r&eacute;s sur la machine o&ugrave; le support de sendfile est
	  d&eacute;faillant.</p>
        </li>
        <li>
          <p>Dans le cas d'un syst&egrave;me de fichiers mont&eacute;
	  sous NFS, le noyau peut s'av&eacute;rer incapable de servir
	  les fichiers r&eacute;seau de mani&egrave;re fiable depuis
	  son propre cache.</p>
        </li>
      </ul>

      <p>Pour les installations o&ugrave; une de ces situations peut se produire,
      vous devez utiliser <code>EnableSendfile off</code> afin de d&eacute;sactiver
      la mise &agrave; disposition de contenus de fichiers par sendfile. (Note : il
      est possible de passer outre cette directive au niveau de chaque
      r&eacute;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&eacute;f&eacute;rence. En particulier,
      Apache avait besoin d'un d&eacute;lai de "mont&eacute;e en puissance" afin d'atteindre
      un nombre de processus enfants suffisant pour supporter la charge qui lui
      &eacute;tait appliqu&eacute;e. Apr&egrave;s le lancement initial des processus enfants par
      <directive module="mpm_common">StartServers</directive>, seulement un
      processus enfant par seconde &eacute;tait cr&eacute;&eacute; afin d'atteindre la valeur de la
      directive <directive module="prefork">MinSpareServers</directive>. Ainsi,
      un serveur acc&eacute;d&eacute; par 100 clients simultan&eacute;s et utilisant la valeur par
      d&eacute;faut de <code>5</code> pour la directive
      <directive module="mpm_common">StartServers</directive>, n&eacute;cessitait
      environ 95 secondes pour lancer suffisamment de processus enfants
      permettant de faire face &agrave; la charge. Ceci fonctionne en pratique pour
      les serveurs en production, car ils sont rarement red&eacute;marr&eacute;s. Ce n'est
      cependant pas le cas pour les tests de r&eacute;f&eacute;rence (benchmarks) o&ugrave; le
      serveur ne fonctionne que 10 minutes.</p>

      <p>La r&egrave;gle "un processus par seconde" avait &eacute;t&eacute; impl&eacute;ment&eacute;e afin
      d'&eacute;viter l'enlisement de la machine dans le d&eacute;marrage de nouveaux
      processus enfants. Pendant que la machine est occup&eacute;e &agrave; lancer des
      processus enfants, elle ne peut pas traiter les requ&ecirc;tes. Mais cette
      r&egrave;gle impactait tellement la perception des performances d'Apache qu'elle
      a d&ucirc; &ecirc;tre remplac&eacute;e. A partir d'Apache 1.3, le code a assoupli la r&egrave;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'&agrave; lancer 32 processus. Il s'arr&ecirc;tera lorsque le
      nombre de processus aura atteint la valeur d&eacute;finie par la directive
      <directive module="prefork">MinSpareServers</directive>.</p>

      <p>Ceci s'av&egrave;re suffisamment r&eacute;actif pour pouvoir en g&eacute;n&eacute;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&eacute;s par seconde, un message est &eacute;mis vers
      le journal des erreurs. Si vous voyez appara&icirc;tre souvent ce genre de
      message, vous devez vous pencher sur ces r&eacute;glages. Pour vous guider,
      utilisez les informations d&eacute;livr&eacute;es par le module
      <module>mod_status</module>.</p>

    <p>&Agrave; mettre en relation avec la cr&eacute;ation de processus, leur destruction
    est d&eacute;finie par la valeur de la directive
    <directive module="mpm_common">MaxConnectionsPerChild</directive>. Sa valeur
    par d&eacute;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&eacute;gl&eacute;e &agrave; une valeur tr&egrave;s basse,
    de l'ordre de <code>30</code>, il est conseill&eacute; de l'augmenter de mani&egrave;re
    significative. Si vous utilisez SunOs ou une ancienne version de Solaris,
    utilisez une valeur de l'ordre de <code>10000</code>  &agrave; cause des fuites
    de m&eacute;moire.</p>

    <p>Lorsqu'ils sont en mode "keep-alive", les processus enfants sont
    maintenus et ne font rien sinon attendre la prochaine requ&ecirc;te sur la
    connexion d&eacute;j&agrave; ouverte. La valeur par d&eacute;faut de <code>5</code> de la
    directive <directive module="core">KeepAliveTimeout</directive> tend &agrave;
    minimiser cet effet. Il faut trouver le bon compromis entre la bande
    passante r&eacute;seau et les ressources du serveur. En aucun cas vous ne devez
    choisir une valeur sup&eacute;rieure &agrave; <code>60</code> seconds, car
    <a href="http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-4.html">
    la plupart des b&eacute;n&eacute;fices sont alors perdus</a>.</p>

    </section>

  </section>

  <section id="compiletime">

    <title>Optimisation de la configuration &agrave; la compilation</title>

    <section>

      <title>Choisir un Module Multi-Processus (MPM)</title>

      <p>Apache 2.x supporte les mod&egrave;les simultan&eacute;s enfichables, appel&eacute;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&eacute;cifiques :
      <module>mpm_netware</module>, <module>mpmt_os2</module> et
      <module>mpm_winnt</module>. Sur les syst&egrave;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'&eacute;volutivit&eacute; du d&eacute;mon httpd :</p>

      <ul>

        <li>Le MPM <module>worker</module> utilise plusieurs processus
	enfants poss&eacute;dant chacun de nombreux threads. Chaque thread g&egrave;re une
	seule connexion &agrave; la fois. Worker est en g&eacute;n&eacute;ral un bon choix pour les
	serveurs pr&eacute;sentant un traffic important car il poss&egrave;de une empreinte
	m&eacute;moire plus petite que le MPM prefork.</li>

	<li>Comme le MPM Worker, le MPM <module>event</module> utilise
	les threads, mais il a &eacute;t&eacute; con&ccedil;u pour traiter davantage de
	requ&ecirc;tes simultan&eacute;ment en confiant une partie du travail &agrave; des
	threads de support, ce qui permet aux threads principaux de
	traiter de nouvelles requ&ecirc;tes.</li>

        <li>Le MPM <module>prefork</module> utilise plusieurs processus enfants
	poss&eacute;dant chacun un seul thread. Chaque processus g&egrave;re une seule
	connexion &agrave; la fois. Sur de nombreux syst&egrave;mes, prefork est comparable
	en mati&egrave;re de vitesse &agrave; worker, mais il utilise plus de m&eacute;moire. De par
	sa conception sans thread, prefork pr&eacute;sente des avantages par rapport &agrave;
	worker dans certaines situations : il peut &ecirc;tre utilis&eacute; avec les
	modules tiers qui ne supportent pas le threading, et son d&eacute;bogage est plus
	ais&eacute; sur les platesformes pr&eacute;sentant un support du d&eacute;bogage des threads
	rudimentaire.</li>

      </ul>

      <p>Pour plus d'informations sur ces deux MPMs et les autres, veuillez
      vous r&eacute;f&eacute;rer &agrave; la <a href="../mpm.html">documentation sur les
      MPM</a>.</p>

    </section>

    <section id="modules">

        <title>Modules</title>

        <p>Comme le contr&ocirc;le de l'utilisation de la m&eacute;moire est tr&egrave;s important
	en mati&egrave;re de performance, il est conseill&eacute; d'&eacute;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 &eacute;limination consiste
	simplement &agrave; commenter la directive
	<directive module="mod_so">LoadModule</directive> associ&eacute;e &agrave; ce
	module. Ceci vous permet de v&eacute;rifier si votre site fonctionne toujours
	apr&egrave;s la suppression de tel ou tel module.</p>

        <p>Par contre, si les modules que vous voulez supprimer sont li&eacute;s
	statiquement &agrave; votre binaire Apache, vous devrez recompiler ce dernier
	afin de pouvoir les &eacute;liminer.</p>

        <p>La question qui d&eacute;coule de ce qui pr&eacute;c&egrave;de est &eacute;videmment de
	savoir de quels modules vous avez besoin et desquels vous pouvez vous
	passer. La r&eacute;ponse sera bien entendu diff&eacute;rente d'un site web &agrave;
	l'autre. Cependant, la liste <em>minimale</em> de modules n&eacute;cessaire &agrave;
	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&eacute;conseill&eacute;.</p>

    </section>

    <section>

      <title>Op&eacute;rations atomiques</title>

      <p>Certains modules, &agrave; l'instar de <module>mod_cache</module> et des
      versions de d&eacute;veloppement r&eacute;centes du MPM worker, utilisent l'API
      atomique d'APR. Cette API propose des op&eacute;rations atomiques que l'on
      peut utiliser pour all&eacute;ger la synchronisation des threads.</p>

      <p>Par d&eacute;faut, APR impl&eacute;mente ces op&eacute;rations en utilisant les
      m&eacute;canismes les plus efficaces disponibles sur chaque plateforme cible
      (Syst&egrave;me d'exploitation et processeur). De nombreux processeurs modernes,
      par exemple, poss&egrave;dent une instruction qui effectue une op&eacute;ration
      atomique de type comparaison et &eacute;change ou compare-and-swap (CAS) au
      niveau mat&eacute;riel. Sur certaines platesformes cependant, APR utilise par
      d&eacute;faut une impl&eacute;mentation de l'API atomique plus lente, bas&eacute;e sur les
      mutex, afin d'assurer la compatibilit&eacute; avec les anciens mod&egrave;les de
      processeurs qui ne poss&egrave;dent pas ce genre d'instruction. Si vous
      construisez Apache pour une de ces platesformes, et ne pr&eacute;voyez de
      l'ex&eacute;cuter que sur des processeurs r&eacute;cents, vous pouvez s&eacute;lectionner une
      impl&eacute;mentation atomique plus rapide &agrave; 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&eacute;faut les op&eacute;rations
	    atomiques bas&eacute;es sur les mutex. Cependant, si vous ajoutez l'option
	    <code>--enable-nonportable-atomics</code> au script configure, APR
	    g&eacute;n&egrave;re un code qui utilise le code op&eacute;ration SPARC v8plus pour des
	    op&eacute;rations de compare-and-swap mat&eacute;riel plus rapides. Si vous
	    utilisez cette option de configure avec Apache, les op&eacute;rations
	    atomiques seront plus efficaces (permettant d'all&eacute;ger la charge du
	    processeur et un plus haut niveau de simultan&eacute;it&eacute;), mais
	    l'ex&eacute;cutable produit ne fonctionnera que sur les processeurs
	    UltraSPARC.
	</li>

        <li>Linux sur x86<br />
            Sous Linux, APR utilise par d&eacute;faut les op&eacute;rations atomiques bas&eacute;es
	    sur les mutex. Cependant, si vous ajoutez l'option
	    <code>--enable-nonportable-atomics</code> au script configure,
	    APR g&eacute;n&eacute;rera un code qui utilise un code d'op&eacute;ration du 486
	    pour des op&eacute;rations de compare-and-swap mat&eacute;riel plus rapides. Le
	    code r&eacute;sultant est plus efficace en mati&egrave;re d'op&eacute;rations atomiques,
	    mais l'ex&eacute;cutable produit ne fonctionnera que sur des processeurs
	    486 et sup&eacute;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> &agrave; la
      construction d'Apache et ajoutez <code>ExtendedStatus On</code> &agrave; sa
      configuration, Apache va effectuer pour chaque requ&ecirc;te deux appels &agrave;
      <code>gettimeofday(2)</code> (ou <code>times(2)</code> selon votre
      syst&egrave;me d'exploitation), et (pour les versions ant&eacute;rieures &agrave; 1.3) de
      nombreux appels suppl&eacute;mentaires &agrave; <code>time(2)</code>. Tous ces
      appels sont effectu&eacute;s afin que le rapport de statut puisse contenir
      des indications temporelles. Pour am&eacute;liorer les performances, utilisez
      <code>ExtendedStatus off</code> (qui est le r&eacute;glage par d&eacute;faut).</p>

    </section>

    <section>

      <title>accept Serialization - points de connexion &agrave; un programme (sockets) multiples</title>

    <note type="warning"><title>Mise en garde :</title>
      <p>Cette section n'a pas &eacute;t&eacute; totalement mise &agrave; 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&eacute; de les utiliser avec prudence.</p>
    </note>

      <p>Ce qui suit est une br&egrave;ve discussion &agrave; propos de l'API des sockets
      Unix. Supposons que votre serveur web utilise plusieurs directives
      <directive module="mpm_common">Listen</directive> afin d'&eacute;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&eacute;ro</em> ou <em>au moins une</em> connexion en attente. Le mod&egrave;le
      d'Apache comporte plusieurs processus enfants, et tous ceux qui sont
      inactifs testent la pr&eacute;sence de nouvelles connexions au m&ecirc;me moment.
      Une impl&eacute;mentation rudimentaire de ceci pourrait ressembler &agrave;
      l'exemple suivant
      (ces exemples ne sont pas extraits du code d'Apache, ils ne sont
      propos&eacute;s qu'&agrave; des fins p&eacute;dagogiques) :</p>

      <highlight language="c">
        for (;;) {
          for (;;) {
            fd_set accept_fds;

            FD_ZERO (&amp;accept_fds);
            for (i = first_socket; i &lt;= last_socket; ++i) {
              FD_SET (i, &amp;accept_fds);
            }
            rc = select (last_socket+1, &amp;accept_fds, NULL, NULL, NULL);
            if (rc &lt; 1) continue;
            new_connection = -1;
            for (i = first_socket; i &lt;= last_socket; ++i) {
              if (FD_ISSET (i, &amp;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&eacute;mentation rudimentaire pr&eacute;sente une s&eacute;rieuse lacune.
      Rappelez-vous que les processus enfants ex&eacute;cutent cette boucle au m&ecirc;me
      moment ; ils vont ainsi bloquer sur <code>select</code> s'ils se trouvent
      entre deux requ&ecirc;tes. Tous ces processus bloqu&eacute;s vont se r&eacute;activer et
      sortir de <code>select</code> quand une requ&ecirc;te va appara&icirc;tre sur un des
      sockets (le nombre de processus enfants qui se r&eacute;activent varie en
      fonction du syst&egrave;me d'exploitation et des r&eacute;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&ecirc;tes que par cet unique socket, et il en sera ainsi
      jusqu'&agrave; ce que suffisamment de nouvelles requ&ecirc;tes apparaissent sur ce
      socket pour les r&eacute;activer tous. Cette lacune a &eacute;t&eacute; document&eacute;e pour la
      premi&egrave;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&egrave;re consiste &agrave; rendre les sockets non blocants. Dans ce cas,
      <code>accept</code> ne bloquera pas les processus enfants, et ils
      pourront continuer &agrave; s'ex&eacute;cuter imm&eacute;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&eacute;activer, tenter un <code>accept</code>
      de la connexion, &eacute;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&ecirc;tes qui arrivent sur d'autres sockets jusqu'&agrave; ce
      qu'ils retournent dans <code>select</code>. Finalement, cette solution
      ne semble pas tr&egrave;s efficace, &agrave; 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&egrave;s courante.</p>

      <p>Une autre solution, celle qu'utilise Apache, consiste &agrave; s&eacute;rialiser les
      entr&eacute;es dans la boucle interne. La boucle ressemble &agrave; ceci (les
      diff&eacute;rences sont mises en surbrillance) :</p>

      <highlight language="c">
        for (;;) {
          <strong>accept_mutex_on ();</strong>
          for (;;) {
            fd_set accept_fds;
            
            FD_ZERO (&amp;accept_fds);
            for (i = first_socket; i &lt;= last_socket; ++i) {
              FD_SET (i, &amp;accept_fds);
            }
            rc = select (last_socket+1, &amp;accept_fds, NULL, NULL, NULL);
            if (rc &lt; 1) continue;
            new_connection = -1;
            for (i = first_socket; i &lt;= last_socket; ++i) {
              if (FD_ISSET (i, &amp;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&eacute;mentent un s&eacute;maphore permettant une exclusion mutuelle. Un seul
      processus enfant &agrave; la fois peut poss&eacute;der le mutex. Plusieurs choix se
      pr&eacute;sentent pour impl&eacute;menter ces mutex. Ce choix est d&eacute;fini dans
      <code>src/conf.h</code> (versions ant&eacute;rieures &agrave; 1.3) ou
      <code>src/include/ap_config.h</code> (versions 1.3 ou sup&eacute;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&ucirc;r.</p>

      <p>La directive <directive module="core">Mutex</directive> permet
      de modifier l'impl&eacute;mentation du mutex <code>mpm-accept</code> &agrave;
      l'ex&eacute;cution. Des consid&eacute;rations sp&eacute;cifiques aux diff&eacute;rentes
      impl&eacute;mentations de mutex sont document&eacute;es avec cette directive.</p>

      <p>Une autre solution qui a &eacute;t&eacute; imagin&eacute;e mais jamais impl&eacute;ment&eacute;e, consiste
      &agrave; s&eacute;rialiser partiellement la boucle -- c'est &agrave; dire y faire entrer un
      certain nombre de processus. Ceci ne pr&eacute;senterait un int&eacute;r&ecirc;t que sur les
      machines multiprocesseurs o&ugrave; plusieurs processus enfants peuvent
      s'ex&eacute;cuter simultan&eacute;ment, et encore, la s&eacute;rialisation ne tire pas
      vraiment parti de toute la bande passante. C'est une possibilit&eacute;
      d'investigation future, mais demeure de priorit&eacute; basse car les serveurs
      web &agrave; architecture hautement parall&egrave;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 &eacute;lev&eacute;es.
      Mais lisez ce qui suit.</p>

    </section>

    <section>

      <title>accept Serialization - point de connexion &agrave; un programme (sockets) unique</title>

      <p>Ce qui pr&eacute;c&egrave;de convient pour les serveurs &agrave; sockets multiples, mais
      qu'en est-il des serveurs &agrave; socket unique ? En th&eacute;orie, ils ne
      devraient pas rencontrer les m&ecirc;mes probl&egrave;mes car tous les processus
      enfants peuvent se bloquer dans <code>accept(2)</code> jusqu'&agrave; ce qu'une
      connexion arrive, et ils ne sont pas utilis&eacute;s &agrave; ne rien faire. En
      pratique, ceci dissimule un m&ecirc;me comportement de bouclage
      discut&eacute; plus haut dans la solution non-blocante. De la mani&egrave;re dont
      sont impl&eacute;ment&eacute;es les piles TCP, le noyau r&eacute;active v&eacute;ritablement tous les
      processus bloqu&eacute;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&eacute;sactivant quand ils s'aper&ccedil;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&ecirc;me pr&eacute;sent. Ceci peut conduire &agrave; la
      m&ecirc;me augmentation de charge &agrave; perte que la solution non blocante au cas
      des sockets multiples peut induire.</p>

      <p>Pour cette raison, il appara&icirc;t que de nombreuses architectures se
      comportent plus "proprement" si on s&eacute;rialise m&ecirc;me dans le cas d'une socket
      unique. Il s'agit en fait du comportement par d&eacute;faut dans la plupart des
      cas. Des exp&eacute;riences pouss&eacute;es sous Linux (noyau 2.0.30 sur un
      biprocesseur Pentium pro 166 avec 128 Mo de RAM) ont montr&eacute; que la
      s&eacute;rialisation d'une socket unique provoque une diminution inf&eacute;rieure &agrave; 3%
      du nombre de requ&ecirc;tes par secondes par rapport au traitement non
      s&eacute;rialis&eacute;. Mais le traitement non s&eacute;rialis&eacute; des sockets uniques induit
      un temps de r&eacute;ponse suppl&eacute;mentaire de 100 ms pour chaque requ&ecirc;te. Ce
      temps de r&eacute;ponse est probablement provoqu&eacute; par une limitation sur les
      lignes &agrave; haute charge, et ne constitue un probl&egrave;me que sur les r&eacute;seaux
      locaux. Si vous voulez vous passer de la s&eacute;rialisation des sockets
      uniques, vous pouvez d&eacute;finir
      <code>SINGLE_LISTEN_UNSERIALIZED_ACCEPT</code> et les
      serveurs &agrave; socket unique ne pratiqueront plus du tout la
      s&eacute;rialisation.</p>

    </section>

    <section>

      <title>Fermeture en prenant son temps (Lingering close)</title>

      <p>Comme discut&eacute; 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&eacute;menter de
      mani&egrave;re <strong>fiable</strong> le protocole, un serveur HTTP doit fermer
      les deux directions d'une communication ind&eacute;pendamment (rappelez-vous
      qu'une connexion TCP est bidirectionnelle, chaque direction &eacute;tant
      ind&eacute;pendante de l'autre).</p>

      <p>Quand cette fonctionnalit&eacute; fut ajout&eacute;e &agrave; Apache, elle causa une
      avalanche de probl&egrave;mes sur plusieurs versions d'Unix &agrave; cause d'une
      impl&eacute;mentation &agrave; courte vue. La sp&eacute;cification TCP ne pr&eacute;cise pas que
      l'&eacute;tat <code>FIN_WAIT_2</code> poss&egrave;de un temps de r&eacute;ponse mais elle ne
      l'exclut pas. Sur les syst&egrave;mes qui n'introduisent pas ce temps de
      r&eacute;ponse, Apache 1.2 induit de nombreux blocages d&eacute;finitifs de socket
      dans l'&eacute;tat <code>FIN_WAIT_2</code>. On peut eviter ceci dans de nombreux
      cas tout simplement en mettant &agrave; jour TCP/IP avec le dernier patch mis &agrave;
      disposition par le fournisseur. Dans les cas o&ugrave; le fournisseur n'a
      jamais fourni de patch (par exemple, SunOS4 -- bien que les utilisateurs
      poss&eacute;dant une license source puissent le patcher eux-m&ecirc;mes), nous avons
      d&eacute;cid&eacute; de d&eacute;sactiver cette fonctionnalit&eacute;.</p>

      <p>Il y a deux m&eacute;thodes pour arriver &agrave; ce r&eacute;sultat. La premi&egrave;re est
      l'option de socket <code>SO_LINGER</code>. Mais le sort a voulu que cette
      solution ne soit jamais impl&eacute;ment&eacute;e correctement dans la plupart des
      piles TCP/IP. Et m&ecirc;me dans les rares cas o&ugrave; cette solution a &eacute;t&eacute;
      impl&eacute;ment&eacute;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&eacute;mente cette solution &agrave; l'aide
      d'une fonction appel&eacute;e <code>lingering_close</code> (d&eacute;finie dans
      <code>http_main.c</code>). La fonction ressemble approximativement &agrave;
      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)) &lt;= 0) {
                break;
              }
              /* just toss away whatever is here */
            }
          }
          
          close (s);
        }
      </highlight>

      <p>Ceci ajoute naturellement un peu de charge &agrave; la fin d'une connexion,
      mais s'av&egrave;re n&eacute;cessaire pour une impl&eacute;mentation fiable. Comme HTTP/1.1
      est de plus en plus pr&eacute;sent et que toutes les connexions sont
      persistentes, la charge sera amortie par la multiplicit&eacute; des requ&ecirc;tes.
      Si vous voulez jouer avec le feu en d&eacute;sactivant cette fonctionnalit&eacute;,
      vous pouvez d&eacute;finir <code>NO_LINGCLOSE</code>, mais c'est fortement
      d&eacute;conseill&eacute;. En particulier, comme les connexions persistantes en
      pipeline de HTTP/1.1 commencent &agrave; &ecirc;tre utilis&eacute;es,
      <code>lingering_close</code> devient une absolue n&eacute;cessit&eacute; (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&eacute;r&ecirc;t &agrave; les supporter).</p>

    </section>

    <section>

      <title>Fichier tableau de bord (Scoreboard file)</title>

      <p>Les processus parent et enfants d'Apache communiquent entre eux &agrave;
      l'aide d'un objet appel&eacute; "Tableau de bord" (Scoreboard). Id&eacute;alement, cet
      &eacute;change devrait s'effectuer en m&eacute;moire partag&eacute;e. Pour les syst&egrave;mes
      d'exploitation auxquels nous avons eu acc&egrave;s, ou pour lesquels nous avons
      obtenu des informations suffisamment d&eacute;taill&eacute;es pour effectuer un
      portage, cet &eacute;change est en g&eacute;n&eacute;ral impl&eacute;ment&eacute; en utilisant la m&eacute;moire
      partag&eacute;e. Pour les autres, on utilise par d&eacute;faut un fichier d'&eacute;change sur
      disque. Le fichier d'&eacute;change sur disque est non seulement lent, mais
      aussi peu fiable (et propose moins de fonctionnalit&eacute;s). Recherchez dans
      le fichier <code>src/main/conf.h</code> correspondant &agrave; votre
      architecture soit <code>USE_MMAP_SCOREBOARD</code>, soit
      <code>USE_SHMGET_SCOREBOARD</code>. La d&eacute;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&eacute;moire
      partag&eacute;e. Si votre syst&egrave;me propose une autre solution pour la gestion de
      la m&eacute;moire partag&eacute;e, &eacute;ditez le fichier <code>src/main/http_main.c</code>
      et ajoutez la portion de code n&eacute;cessaire pour pouvoir l'utiliser dans
      Apache (Merci de nous envoyer aussi le patch correspondant).</p>

      <note>Note &agrave; caract&egrave;re historique : le portage d'Apache sous Linux
      n'utilisait pas la m&eacute;moire partag&eacute;e avant la version 1.2. Ceci entra&icirc;nait
      un comportement tr&egrave;s rudimentaire et peu fiable des versions ant&eacute;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&eacute;s
      dynamiquement (ce qui est probablement le cas si vous &ecirc;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&eacute;finition
      <code>-DDYNAMIC_MODULE_LIMIT=0</code> &agrave; la construction de votre serveur.
      Ceci aura pour effet de lib&eacute;rer la m&eacute;moire RAM allou&eacute;e pour le
      chargement dynamique des modules.</p>

    </section>

  </section>

  <section id="trace">

    <title>Appendice : Analyse d&eacute;taill&eacute;e d'une trace</title>

    <p>Voici la trace d'un appel syst&egrave;me d'Apache 2.0.38 avec le MPM worker
    sous Solaris 8. Cette trace a &eacute;t&eacute; collect&eacute;e &agrave; l'aide de la commande :</p>

    <example>
      truss -l -p <var>httpd_child_pid</var>.
    </example>

    <p>L'option <code>-l</code> demande &agrave; truss de tracer l'ID du LWP
    (lightweight process--la version de Solaris des threads niveau noyau) qui
    invoque chaque appel syst&egrave;me.</p>

    <p>Les autres syst&egrave;mes peuvent proposer des utilitaires de tra&ccedil;age
    des appels syst&egrave;me diff&eacute;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&eacute; un fichier statique de 10 ko au
    d&eacute;mon httpd. Le tra&ccedil;age des requ&ecirc;tes pour des contenus non statiques
    ou comportant une n&eacute;gociation de contenu a une pr&eacute;sentation
    diff&eacute;rente (et m&ecirc;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 &agrave; l'&eacute;coute s'ex&eacute;cute &agrave; l'int&eacute;rieur de
    LWP #67.</p>

    <note>Notez l'absence de la s&eacute;rialisation d'<code>accept(2)</code>. Sur
    cette plateforme sp&eacute;cifique, le MPM worker utilise un accept non s&eacute;rialis&eacute;
    par d&eacute;faut sauf s'il est en &eacute;coute sur des ports multiples.</note>

    <example>
<pre>/65:    lwp_park(0x00000000, 0)                         = 0
/67:    lwp_unpark(65, 1)                               = 0</pre>
    </example>

    <p>Apr&egrave;s avoir accept&eacute; la connexion, le thread &agrave; l'&eacute;coute r&eacute;active un
    thread du worker pour effectuer le traitement de la requ&ecirc;te. Dans cette
    trace, le thread du worker qui traite la requ&ecirc;te est associ&eacute; &agrave;
    LWP #65.</p>

    <example>
<pre>/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0</pre>
    </example>

    <p>Afin de pouvoir impl&eacute;menter les h&ocirc;tes virtuels, Apache doit conna&icirc;tre
    l'adresse du socket local utilis&eacute; pour accepter la connexion. On pourrait
    supprimer cet appel dans de nombreuses situations (par exemple dans le cas
    o&ugrave; il n'y a pas d'h&ocirc;te virtuel ou dans le cas o&ugrave; les directives
    <directive module="mpm_common">Listen</directive> contiennent des adresses
    sans caract&egrave;res de substitution). Mais aucun effort n'a &eacute;t&eacute; accompli &agrave; 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&eacute;moire dans le tas. Ceci est
    rarement visible dans une trace d'appel syst&egrave;me, car le d&eacute;mon httpd
    utilise des allocateurs m&eacute;moire de son cru (<code>apr_pool</code> et
    <code>apr_bucket_alloc</code>) pour la plupart des traitements de requ&ecirc;tes.
    Dans cette trace, le d&eacute;mon httpd vient juste de d&eacute;marrer, et il doit
    appeler <code>malloc(3)</code> pour r&eacute;server les blocs de m&eacute;moire
    n&eacute;cessaires &agrave; la cr&eacute;ation de ses propres allocateurs de m&eacute;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&egrave;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&ecirc;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&eacute;mon httpd a &eacute;t&eacute; configur&eacute; 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&eacute;pertoire
    du chemin du fichier demand&eacute;, ni besoin de v&eacute;rifier la pr&eacute;sence de fichiers
    <code>.htaccess</code>. Il appelle simplement <code>stat(2)</code> pour
    v&eacute;rifier d'une part que le fichier existe, et d'autre part que c'est un
    fichier r&eacute;gulier, et non un r&eacute;pertoire.</p>

    <example>
<pre>/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269</pre>
    </example>

    <p>Dans cet exemple, le d&eacute;mon httpd peut envoyer l'en-t&ecirc;te de la r&eacute;ponse
    HTTP et le fichier demand&eacute; &agrave; l'aide d'un seul appel syst&egrave;me
    <code>sendfilev(2)</code>. La s&eacute;mantique de sendfile varie en fonction des
    syst&egrave;mes d'exploitation. Sur certains autres syst&egrave;mes, il faut faire un
    appel &agrave; <code>write(2)</code> ou <code>writev(2)</code> pour envoyer les
    en-t&ecirc;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 &agrave; <code>write(2)</code> enregistre la requ&ecirc;te dans le journal
    des acc&egrave;s. Notez qu'une des choses manquant &agrave; cette trace est un appel &agrave;
    <code>time(2)</code>. A la diff&eacute;rence d'Apache 1.3, Apache 2.x utilise
    <code>gettimeofday(3)</code> pour consulter l'heure. Sur certains syst&egrave;mes
    d'exploitation, comme Linux ou Solaris, <code>gettimeofday</code> est
    impl&eacute;ment&eacute; de mani&egrave;re optimis&eacute;e de telle sorte qu'il consomme moins de
    ressources qu'un appel syst&egrave;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&eacute;livrer et
    se bloque jusqu'&agrave; ce que le thread en &eacute;coute lui assigne une autre
    connexion.</p>

    <example>
<pre>/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)</pre>
    </example>

    <p>Pendant ce temps, le thread &agrave; l'&eacute;coute peut accepter une autre connexion
    &agrave; partir du moment o&ugrave; il a assign&eacute; la connexion pr&eacute;sente &agrave; un thread de
    worker (selon une certaine logique de contr&ocirc;le de flux dans le MPM worker
    qui impose des limites au thread &agrave; l'&eacute;coute si tous les threads de worker
    sont occup&eacute;s). Bien que cela n'apparaisse pas dans cette trace,
    l'<code>accept(2)</code> suivant peut (et le fait en g&eacute;n&eacute;ral, en situation
    de charge &eacute;lev&eacute;e) s'ex&eacute;cuter en parall&egrave;le avec le traitement de la
    connexion qui vient d'&ecirc;tre accept&eacute;e par le thread de worker.</p>

  </section>

</manualpage>

