Attention, cet article a été posté en 2009. Il est
possible que les informations mentionnées ne soient plus d'actualité, ou que mon
opinion ait évolué. Merci d'en tenir compte lors de votre lecture.
Petit, je souhaitais devenir chirurgien. Ce rêve m’a laissé quelques séquelles, j’adore opérer à cœur ouvert : prendre un programme, le découper en morceau, et comprendre ses forces et ses faiblesses en partant de l’intérieur. Aujourd’hui, j’ai décidé de m’attaquer à la nouvelle monture de Wordpress, dans le but d’optimiser le machin.
Première étape, l’installation. Je ne détaille pas le processus, vous le connaissez probablement sur le bout des doigts. Dix minutes top chrono, le temps de dézipper la bête, le tout est installé. Le scalpel à droite, la morphine à gauche, l’opération peut commencer.
Après un premier état des lieux rapide, je me dirige directement vers le centre du cerveau : les requêtes SQL. Une ligne de code ajoutée par-ci, une autre par là, elles défilent sur mon écran au fil de ma navigation. Pour information, j’ai juste trifouillé la méthode query() du fichier /wp-includes/wp-db.php pour ajouter un simple :
Première constatation, ces requêtes sont nombreuses. Au moins une dizaine par page, en moyenne. Et encore, je n’ose pas vous parler de l’interface d’administration. De plus, nombre d’entre elles sont redondantes, plusieurs pourraient être fusionnées, d’autres supprimées. Je pense notamment à celles permettant de charger les options de configuration de votre blog : ces options changent tous les 36 du mois, les mettre en cache me semble inévitable, pourquoi ne le font-ils pas ? Idem pour les liens ou les catégories, placés dans la sidebar.
Pour m’aider dans l’analyse de ces requêtes, j’approfondis le bout de code donné plus haut (ne fuyez pas, je vous l’explique juste après, en bon français) :
echo $query;
if ( substr($query, 0, 7) == 'SELECT ' )
{
$r = mysql_query('EXPLAIN '.$query);
echo '<pre>';
while ( $d = mysql_fetch_assoc($r) )
{
var_dump($d);
}
echo '</pre>';
}
Ce bout de code permet d’exploiter la puissance du gestionnaire de base de données : pour chaque requête, je lui demande de m’expliquer comment il va la traiter. Cela permet de voir en un coup d’œil si la requête est optimisée, et si des améliorations peuvent être apportées à ce niveau.
Les connaisseurs noteront que je n’utilise pas l’objet MySqL proposé par Wordpress : je vais au plus simple, pour limiter au maximum les risques d’erreur, qui pourraient provoquer des jugements trop hâtifs.
Je suis plutôt content à ce niveau, toutes les requêtes sont relativement optimisées. Revers de la médaille, cela veut également dire que j’allègerai relativement peu la bête en cherchant de ce côté. Flûte.
Prochaine opération, les timers. Modifier le code en plaçant des témoins à différents endroits stratégiques permet de repérer facilement les goulots d’engorgement, pour cibler les zones à optimiser en priorité. Pour cela, on démarre le chrono au tout début du fichier :
define("TIMER_START", microtime(true));
puis on affiche le temps écoulés depuis le début à plusieurs reprises :
echo microtime(true) – TIMER_START;
Bingo, deux goulots repérés. Sur un total de 430 millisecondes en moyenne pour charger la page (c’est énorme : à titre de comparaison, Blogonet affiche la Home en moins de 30 millisecondes, sur la même bécane) :
- 100 ms sont utilisées par le chargement d’une 15ène de fichiers, définissant des centaines de fonctions, sur plusieurs dizaines de milliers de lignes. Peu de solutions à proposer à ce niveau (ou du moins, pas au niveau du code en lui-même, il faudra plutôt toucher à configuration du serveur, en mettant en place un cache OP-Code).
- 200 ms environ sont utilisées par le moteur de langage : après avoir analysé la chose, la solution est très puissante, mais également très très lourde. Pour corriger le tir, un fichier de cache peut être mis en place sur l’objet ainsi généré.
Résultat, en appliquant les quelques conseils de l’article, j’arrive à franchir la barre des 180 ms, en moyenne. Le tout avec moitié-moins de requêtes. C’est encore beaucoup, j’en suis conscient, mais ça permet déjà de diviser les ressources consommées par deux (et donc de prendre un serveur deux fois moins cher ?).
Bien entendu, ça ne remplacera jamais un système de cache évolué. D’ailleurs, un jour, je regarderai ce qu’ils ont dans le ventre, eux aussi. Il y a peut être moyen d’optimiser encore.
crédit image