Publié par le 2 août 2009, 2 commentaires

L’optimisation de son site Internet …. Très grande problématique, bien souvent compliqué à résoudre, tant de chose pouvant être à l’origine du problème.

Commençons par cette vidéo de PHPTV de décembre 2008 :

Ensuite, attaquons un petit récapitulatif :

  1. Différence back/front.
  2. Optimisation du back.
  3. Optimisation du front.

1 – Différence back/front

Sur 100 % du temps passé pour charger une page HTML (avec PHP dérrière bien sûr), seulement 10 % maximum sont consacré à PHP. Les 90 % restant, eux, sont liés au temps de transfert du code HTML du serveur vers le client (images, css, js, etc. compris).

Vous comprenez rapidement que le code PHP n’est pas priorité : 40 % de gain sur 10 % du temps total ne représente rien par rapport à 40 % des 90 % du front.

Cela ne veux pas dire qu’il ne faut pas optimiser le PHP, cela veux seulement dire que dans une politique d’optimisation immédiate, mieux vaut passer 2 jours sur le front que sur le back, le gain sera nettement supérieur.

2 - Optimisation du back

On va quand même en parler, car on peut toujours gagner quelques milisecondes.

La première chose à faire, c’est de mettre en place un « monitoring » de temps, c’est à dire un petit script qui permettrait de savoir combien temps notre code PHP a mis pour s’executer.

Sur la page PHP à monitorer, nous allons ajouter en tout début de la page (juste après le <?php) :

$tempDeDebut = microtime();
Juste pour information, cette fonction native « microtime() » n’est disponible que sous PHP 5.

Ensuite, en bas de page, à la fin, en dernier, nous allons mettre :

echo microtime()-$tempDeDebut;

Ainsi, à l’affichage de la page, nous pourrons visualiser combien de temps notre page à mis pour se générer (vous pouvez voir un exemple en bas de cette page).

Juste pour information, si vous dépassez les 1 secondes, c’est qu’il y a du travail sur le back :-D

 

Ensuite, si votre code PHP effectue des connexions à la base de données MYSQL ou MSSQL (PHP sans BDD ne sert « à rien »), nous allons voir comment optimiser nos requêtes SQL facilement en deux points :

Optimisation des index :

Dans votre SGBD (Système de Gestion de Base de Données), je parlerai principalement de MYSQL, nous allons gérer les index des tables.

Avant tout, qu’est ce qu’un index. Un index, c’est un cache servant de sommaire à votre table et permettant au SGBD de rechercher plus vite une données sur une colonne données. Un index est toujours lié à une ou plusieurs colonnes.

Sous PHPMYADMIN ou MySQL Administrator Tool, il est d’une simplicité de créer un index.

Les index se mettent principalement sur la clé primaire, et sur les clés étrangères, mais on peut aussi en ajouter sur les colonnes de recherche.

Exemple :

Deux tables, une catégories et une autre topic.

Catégorie : cat_id, cat_libelle.
Topic : topic_id, topic_sujet, topic_texte, topic_id_categorie.

Nous allons créer un index pour :
- topic_id
- topic_sujet
- topic_id_categorie

Ainsi, les recherches (CLAUSE WHERE) sur l’id du topic, sur son sujet, ou sur sa catégorie seront fortement améliorer en terme de temps et de ressource.

Seul hic, les index prennent de la place dans la base de données et peuvent la faire grossir rapidement. A utiliser seulement lorsque nous ne sommes pas restraint en taille de BDD. Juste pour information au passage, MySQL peut sans aucun problème des bases de données plusieurs Go, ainsi que des tables de plusieurs centaines de milier d’enregistrement.

Aussi, n’abuser pas des index, indexer tous les champs d’une colonne ne sert à rien puisque l’on met au même rang tous les champs, le seul effet sera de surcharger et faire grossir inutilement la base de données.

Reconstruction des index : REPAIR et OPTIMIZE :

Lorsque nous avons correctement indexé notre base de données et ses tables, il est nécessaire régulièrement de recontruire ses index afin de supprimer les index des enregistrement supprimés ou modifiés.

Pour cela, deux fonctions natives de MySQL existent, ce sont REPAIR et OPTIMIZE.

L’une répare les index, l’autre les optimises (très difficile, non ?).

Sur une base de données à forte utilisation, je vous conseillerai de faire ces requêtes une fois par jour, au matin vers 6 h, avant la grosse affluence. Sinon, une fois par semaine est largement sufisant.

Je vous renvoi à l’utilisation des tâches CRON ainsi qu’à la DOC MySQL pour la syntax exacte.

2 - Optimisation du front

La grosse partie arrive. L’optimisation du frontend ne s’effectue pas sur un seul point, mais sur une multitude de petite optimisation qui font au final gagner plusieurs secondes (je parle d’expérience).

Comment voir si mon front est optimiser ?

L’utilisation de Firefox est nécessaire, car le plugin Firebug couplé avec Yslow permet de visualiser le temps de chargement des composants de la page, ainsi que d’évaluer chaque composant. Ils permettent aussi de voir le cache utilisé, etc.

Les requêtes HTTP :

Le nombre de requête HTTP pour le chargement d’une page HTML doit être le minimum possible, c’est à dire qu’il doit y avoir le moins d’élément externe à charger par domaine/sous-domaine.
Effectivement, à chaque image, chaque image-background, chaque fichier CSS, ou encore chaque fichier JavaScript, une requête HTTP est lancé.

Les navigateurs, eux, ne peuvent pas gérer toutes ces requêtes simultanément, donc le téléchargement de ces fichiers se fait en plusieurs fois et prend donc plus de temps. En plus, chaque domaine/sous-domaine est limiter en nombre simultané.

Exemple :    

  • Firefox 2 permet de télécharger 2 requêtes HTTP simultanément.
  • Firefox 3 permet de télécharger 6 requêtes HTTP simultanément.
  • Internet Explorer <=7 permet de télécharger 2 requêtes HTTP simultanément.
  • Internet Explorer 8 permet de télécharger 6 requêtes HTTP simultanément.

Ces données sont valides par domaine/sous-domaine, mais la limite de 4 domaines/sous-domaines est à respecter, au delà, l’effet ne serait pas visible.

Donc, concrètement, il faudrait faire :    

  • JavaScript sur js.mondomaine.com
  • CSS sur css.mondomaine.com
  • Images sur images.mondomaine.com

Les SPRITES :

Les Sprites, ce sont des images contenant plusieurs images. Effectivement, le téléchargement d’une seuls grande image contenant plusieurs petites, est plus rapide que de télécharger plusieurs petites. Ensuite, que ce soit des images ou des image-background, il suffit de spécifier les dimensions, le top, et le left de l’image dans le Sprites. Ainsi, on appel à chaque fois la même image.

La conception des sprites peut se faire avec des logiciels d’image comme GIMP ou PhotoShop, le calcule des dimensions se fera avec les règles de chaque logiciels.

Les PNG :

L’utilisation des PNG à la place des GIF et des JPEG est préférables. Effectivement, les PNG possède l’avantage de gérer les transparences, et sont plus légé que les autres format d’image. IE 7 et 8, ainsi que Firefox gèrent très bien les PNG. Pour que IE 6 et infèrieurs puissent gérer les PNG, je vous renvois à ce post : http://www.remy-solnais.com/png-ie-6/ où j’explique comment appliquer un patch de gestion des PNG.

Les dates d’expirations:

Le premier élément utilisable en HTML pour optimiser le chargement, c’est d’utiliser le cache du navigateur client. Effectivement, par défaut (sauf modification effectué par l’utilisateur), les navigateurs web comme IE et Firefox possède un cache permettant de stocker les fichiers web et de les réutiliser si besoin au lieu de les retélécharger.

Ce système de cache est à mettre en place pour toutes les requêtes standards, images, css, et JS. Les pages HTML elles auront besoins d’être mises à jour pour pouvoir afficher les modifiations.

Afin de forcer le navigateur web à mettre les données en cache, il faut que le serveur web lui spécifie, et pour cela, deux manières existent :   

  • Avec PHP en forçant les entêtes.
  • Avec Apache/.htaccess en forçant les entêtes.

Avec PHP :

header('Expires: '.date('r',(time()+(365*24*60*60)))); // on spécifie une date d'expiration dans le futur
header('Cache-Control: max-age=3600, must-revalidate'); // l'age max sera de 1 heure

 Avec Apache :

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2012 20:00:00 GMT"
</FilesMatch>

Ainsi, on va pouvoir spécifier des entêtes avec des dates d'expiration pour des types de fichiers spécifiques.

La compression avec Gzip/Deflate :

Très peu connus des développeurs, la compression est une technique complémentaire pour gagner de la bande passante et du temps de chargement. Géré en natif par les navigateurs, et optionel coté serveur Apache, cette technologie est d’une simplicité à mettre en place.

Un simple module à activer sous Apache : pour cela, et sous linux, je vous conseil de passer par Webmin (debian, red hat, Ubuntu, etc.) sir vous êtes sur un dédié, si vous êtes sur mutualisé, il se peut que cette fonctionnalité soit activer par défaut (voir avec hébergeur).

Une fois le module activé, il suffit de forcer les entêtes avec PHP :

header('Accept-Encoding: gzip, deflate');

Les codes d’inclusions :

Afin d’optimiser le chargement des librairies externes (CSS et JS), il ne suffit pas de les placer n’importe où, ou bêtement dans la balise HEAD du code HTML.

Le CSS lui se place dans le HEAD HTML, comme appris basiquement à l’école. Le HTML pourra ainsi accéder facilement aux différents styles.

Pour le JS, c’est plus compliqué. Le mieux étant de placer les inclusions juste avant la fermeture de la balise BODY. Effectivement, le code HTML étant déjà chargé, le navigateur pourra ainsi commencer à afficher la page web pendant qu’il finira de charger les librairies JavaScript. La seule contrainte ici, est de bien gérer l’execution de code JS avec un onload sur la body en JS pur, ou avec un $(document).ready en jQuery.

Aussi, en rapport avec le nombre de requête, il est préférable de charger un seul fichier CSS et un seul fichier JS, dans lesquels les espaces blancs inutile, l’indentation, les commentaires et les retours à la lignes auront été supprimé : toutes ces données inutiles pour l’execution du code représentent jusqu’à 30 % du poids du fichier !!

Les CDN :

Pour finir, vous pouvez user d’un CDN (Content Délivery Network), c’est un prestataire qui est implanté chez les différents fournisseurs d’accès à Internet et qui propose la mise en cache de certains de vos pages Internet directement sur ses serveurs et dans les datacenters des FAI. Ainsi, lorsque l’utilisateur pointe sur une de vos URL, il consulte un cache directement sur le réseau de son FAI, la réponse est plus rapide.

Le seul point négatif, cette technique possède un coût énorme et demande une rentabilité réel.

Akamai est un prestataire proposant d’optimiser le chargement des page web.

Le chargement dynamique :

Le chargement dynamique relève d’une bonne logique : pourquoi ne pas charger les librairies avant d’en avoir besoin ?

Vous pouvez forcer la mise en cache de certaines librairies JS et certaines feuilles de style avant d’en avoir besoin, ainsi lorsque vous voudrez vous en servir, le chargement de la librairie ne sera plus nécessaire.

Attention par contre à ne pas surcharger une page et à la rendre trop longue, les visiteurs partirai immédiatement.

Dans le cas d’un Intranet, il peut être intéressant de charger ces librairie sur la page d’identification. Sur un site Internet, il suffit de les charger avec JavaScript tout au long de la navigation de l’utilisateur.

Je vous conseillerai d’utiliser d’utiliser les objets image e JavaScript, ainsi que la construction dynamique de l’arbre DOM HTML pour l’ajout de balise STYLE et SCRIPT.

 

Des exemples de code et des démonstrations seront bientôt mises en ligne …

Tags: , , , , , , , , , , , ,

2 commentaires

Flux RSS des commentaires de cet article. TrackBack URL

Laisser un commentaire

*