10 sept. 2009

Performance du serveur

Développer un site web rapide (1/3)

Un internaute a eu la gentillesse d’appeler une page de votre site web. Votre serveur va-t’il la produire aussi rapidement que possible ? Voici quelques outils pour tirer ceci au clair…

Mesurer

Trouver le problème, c’est trouver la solution ; sortons donc notre micro-chronomètre pour mesurer le temps que le script mets à s’exécuter.
Voici une petite fonction PHP (cadeau !) qui fonctionne comme un chronomètre.

function michronometre(){
global $_MICHRO;
list($usec, $sec) = explode(" ", microtime());
if(isset($_MICHRO)){
return ((float)$usec + (float)$sec)-$_MICHRO;
}else{
$_MICHRO=((float)$usec + (float)$sec); return 0;
}
}

Appelez une première fois la fonction (michronometre();), le compteur démarre. Regardez le compteur à n’importe quel moment pour voir le temps affiché (echo michronometre();).
Vous pouvez le regarder à différents endroits de la page pour voir quelle portion de code est à inspecter pour optimiser.
Le temps obtenu sera d’autant meilleur que votre serveur est bon. Mais de manière générale, on fait avec ce qu’on a…
En ce qui concerne Nooxt, la page la plus complexe est produite en un peu plus d’une demi-seconde.

Syntaxes PHP

Pour gagner quelques microsecondes, jetez un oeil à la syntaxe de votre code PHP : les “switch” sont plus performants que les “if…elseif…else”, les guillemets simples que les guillemets doubles (même si c’est moins vrai, voire même faux sur les dernières versions de PHP),…
Le site The PHP Benchmark répertorie des tests de rapidité pour différentes syntaxes.
Cela dit, n’espérez pas tirer grand chose de ce côté là.

Base de données

Le plus chronophage (un joli néologisme typiquement SSII-ien) restent les appels à la base de données : tentez de regrouper vos requêtes en une seule (avec les jointures et les SELECT imbriqués) et, évidemment, banissez les requêtes au sein de boucles.

Cache des pages et des données

Pour savoir comment mettre en cache une page, il suffit de distinguer deux grands types de pages :

  • les pages entièrement dynamiques qui devront être différentes à chaque chargement puisqu’elles vont chercher des nouvelles données ;
  • les pages qui sont modifiées une fois pour toute côté serveur.

Pour les premières, une page HTML sera affichée beaucoup plus rapidement : vous pouvez soit la produire manuellement (en copiant-collant le code généré HTML par le PHP dans un fichier HTML), soit activer le cache de votre moteur de template (si vous en avez un).
Pour les secondes, le recours au PHP sera obligatoire. Mais, au sein d’une même page, vous pouvez distinguer ce qui nécessite réellement un recalcul à chaque chargement de la page… et les autres.
Sur Nooxt, pour calculer des probabilités de présence, des statistiques sont réalisées sur tous les événements puis appliquées à l’événement en cours. Pour éviter ces deux calculs à chaque page, le premier est calculé une fois pour toute et est stocké en session (dans la variable $_SESSION).

Attendez, je n’ai pas fini de

Lorsque vous faites des “echo” ou “print_r”, les informations ne sont pas envoyées aussitôt : ce n’est qu’à la fin du script que tout est envoyé d’un bloc. Mais pourquoi attendre que toute votre page ne soit calculée avant de commencer à l’envoyer à votre internaute ? Vous pouvez demander au serveur de faire parvenir au client ce qui a déjà été affiché en utilisant la fonction flush() [edit: et ob_flush(), merci Thomas].
L’usage le plus courant est d’utiliser cette fonction juste après le “</head>” dans le code HTML, pour que le navigateur puisse commencer à charger les fichiers externes pendant que le reste de la page est généré.

Dans le prochain épisode…

Votre page a été générée aussi rapidement que possible mais parviendra-t’elle à la vitesse de l’éclair au navigateur ? Melany avouera-t’elle son adultère à Jason ?

2 commentaires

  1. Thomas, 14 octobre 2009

    Pour “forcer” l’affichage à proprement parler par le navigateur (qui possède lui aussi un cache), flush() doit être agrémenté de ob_flush().

    ex :
    <?php
    for($i=1;$i<=10;$i++){
    echo "Loop $i : ".date('H:i:s')."”;
    flush(); ob_flush();
    sleep(1);
    }
    ?>

    Pas d’amélioration de performance pour autant, juste une preuve du chargement en cours ;)

  2. Victor, 2 novembre 2009

    En réponse à Thomas :
    S’il ne s’agit pas à proprement parlé d’une amélioration de performance du serveur, un “flush” prématuré permet de renforcer “l’impression de vitesse” (puisque des choses commencent à apparaître à l’écran plus vite) et cela permet au navigateur de composer la page et à charger les fichiers externes.
    Avec cette mise en parallèle des traitements, il y a bien un gain de performance… pour l’internaute !

Laisser un commentaire