Optimisation des performances de vos sites

De PHPNET Wiki
Aller à : navigation, rechercher

Il existe plusieurs façons d'améliorer les performances de vos sites, ces méthodes sont relativement génériques et ne devraient pas poser de réels soucis dans la majorité des cas d'utilisation mais nous vous recommandons de ne pas les mettre en œuvre si vous ne les comprenez pas.


Définir des dates d'expiration pour les fichiers statiques pour forcer leur mise en cache par le navigateur client

Une méthode simple consiste à utiliser les modules expirés et headers de apache pour jouer sur les expirations des fichiers en cache côté navigateur, elle a l'avantage d'être utilisable sur tous les types d'hébergements (mutualisé, Prémium, VDS ou Dédié) :

Afin d'éviter que les navigateurs aient à recharger à chaque visite (ou changement de page sur un même site par exemple) certains fichiers statiques (fichiers CSS, images ou scripts Javascript par exemple) parfois partagés sur différentes pages du site, il est possible de donner des dates d'expiration pour certains fichiers/types de fichiers côté serveur (par défaut le serveur ne donne aucune directive et c'est au navigateur de décider s'il doit ou non redemander le(s) fichier(s) au serveur et quand les recharger. Il est donc possible de diminuer le nombre de fichiers que le navigateur du visiteur a redemandé et éventuellement rechargé à chaque page ou visite et donc permettre un chargement plus rapide du site (notamment en cas de connexion lente ou de site dont le poids est important).

Vous pouvez observer le comportement de votre navigateur (et du serveur) en utilisant par exemple le module Firebug pour Firefox onglet réseau, si en passant d'une page à une autre il y a des requêtes ayant comme code réponse 304 Not Modified (colonne Statut), c'est que le navigateur a redemandé au serveur le fichier mais que celui là n'ayant pas "expiré" ni changé n'a pas fait re-télécharger au navigateur le fichier. Si certains fichiers sont en code 200 mais grisés c'est que le navigateur n'a même pas fait de demande au serveur et a directement affiché le fichier qu'il possédait dans son cache.

Pour savoir si un Etag à été envoyé, ou retrouver une date d'expiration pour un fichier ou une page, cliquez sur le [+] à gauche de la requête GET correspondant et regardez dans la rubrique "Réponses" de l'onglet "En-Têtes"

Vous pourrez y voir par exemple :

Date	Wed, 30 Mar 2011 16:30:50 GMT
Server	Apache/2.2.17
Last-Modified	Tue, 29 Mar 2011 23:58:50 GMT
Etag	"179abc5-5921-49fa7d7758280"
Accept-Ranges	bytes
Cache-Control	max-age=172800
Expires	Fri, 01 Apr 2011 16:26:03 GMT
Vary	Accept-Encoding
Content-Encoding	gzip
Content-Length	5716
Content-Type	text/css

Où l'on peut voir qu'un Etag est fourni (voir plus loin), que la dernière requête au fichier date du 30/03/2011 à 16:30, que la dernière modification du fichier (côté serveur) date du 29/03/2011 et que ce dernier expirera le 01/04/2011 et qu'il ne devra pas rester plus de 172800 secondes en cache côté client (au delà, si ce n'est pas déjà fait, le navigateur l'éliminera tout seul de son cache).


Vous pouvez pour cela utiliser un fichier .htaccess à la racine du site en question en ajoutant par exemple :

   <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
       FileEtag none
       Header unset Etag
   </FilesMatch>
   ExpiresActive on
   ExpiresByType image/jpg "access plus 4 days"
   ExpiresByType image/gif "access plus 7 days"
   ExpiresByType image/jpeg "access plus 4 days"
   ExpiresByType image/png "access plus 4 days"
   ExpiresByType image/x-icon "access plus 7 days"
   ExpiresByType text/css "access plus 48 hours"
   ExpiresByType application/javascript "access plus 48 hours"
   ExpiresByType application/x-javascript "access plus 48 hours"
   ExpiresByType application/x-shockwave-flash "access plus 48 hours"
   ExpiresDefault "access plus 1 days"

La première partie (dans la directive FilesMatch) fait que tous les fichiers ayant pour extension .ico, .pdf, .flv... n'auront pas d'Etag et que ce dernier ne sera pas transmis.

Le Etag est un identifiant crée par le serveur Apache pour chaque fichier, si ce dernier est modifié le tag changera ; cela permet donc au navigateur de comparer le tag envoyé par le serveur à celui qu'il a en cache afin de pouvoir récupérer en cas de différence à nouveau le fichier.

Le problème est que l'entête Etag est redondant avec l'entête "Last-Modified" également envoyé par Apache, cette entête n'étant précise qu'à la seconde près elle peut ne pas suffire dans le cas de fichiers dynamiques (fichiers générés à la volée par des scripts PHP par exemple) si ces derniers ont été modifiés plus d'une fois par seconde mais se révéler inutile dans le cas de fichiers CSS ou Javascript n'étant modifiés que rarement (et manuellement) par exemple.

Si le Etag est activé, à chaque demande de fichier, le serveur Apache régénérera un Etag en vérifiant les dates de dernières modifications du fichier, sa taille et où il est situé sur le système de fichier; cela consommera des ressources et prendra plus du temps que de seulement récupérer la date de dernière modification (qui est elle aussi fournie par défaut), cela implique également que le navigateur doit demander l'Etag, vérifier s'il correspond à celui qu'il a en cache avant de redemander éventuellement le fichier, si les Etag sont désactivés le navigateur ne demandera pas le fichier s'il l'a déjà en cache et qu'il n'est pas "expiré".

Il est également possible de désactiver le header "Last-Modified" en rajoutant au sein du tag FilesMatch : Header unset Last-Modified

Il est recommandé de bien tester le comportement du navigateur si Etag et Last-Modified sont désactivés et de régler en fonction les durées d'expiration avec le mod_expires.
Documentation officielle du mod_headers


Dans la deuxième partie de l'exemple, la directive ExpiresByType suivie du mimetype permet de définir la durée de validité des fichiers d'une extension précise après le dernier accès par l'utilisateur. Cela permet par exemple à un navigateur de ne pas revérifier les fichiers jpg qu'il a en cache pendant une durée de 4 jours en gardant "en priorité" les fichiers qui ont une expiration plus lointaine par rapport à ceux qui n'en ont pas de définie.
Documentation officielle du mod_expires

Utilisation d'un module de cache PHP

Il existe principalement deux types de cache en PHP :

Le cache applicatif

Le cache applicatif est intégré à l'application PHP et va permettre de ne pas recalculer à chaque accès à une page tout le code, principalement certaines parties ne changeant pas à chaque accès (par exemple: la mise en page dont la majeure partie ne changera pas, l'inclusion de texte contenu dans un fichier n'ayant pas été modifié depuis le dernier accès ou des calculs qui sont récurrents avec des paramètres identiques).

Le "résultat" du traitement de ces parties de codes qui ne change pas est sauvegardé et ensuite repris directement à la prochaine utilisation, évitant ainsi certains calculs/accès disque inutiles, cela évite également d'avoir à re-récupérer certaines données auprès du serveur de bases de données.

La plupart des framework PHP tels que Symfony ou Zend proposent de manière transparente pour le développeur/utilisateur un système de cache, il en va de même pour la plupart des CMS et autres outils PHP tels que PHPBB, Prestashop ou encore Wordpress qui intègrent des systèmes de cache (parfois sous forme de modules) qui ne sont pas activés par défaut mais qui une fois activés permettent d'augmenter drastiquement les performances.

Ce type de cache est généralement désactivé par défaut car lorsque l'on modifie par exemple un thème (ou template), ce dernier pourra ne pas être "re-calculé" immédiatement et donc ne pas afficher les modifications apportées directement, il est donc recommandé lorsque l'on configure, code ou modifie le thème d'un site de désactiver le cache (ou forcer sa re-création quand possible après avoir apporté les modifications).

Ce type d'optimisation est probablement l'un des plus intéressants au niveau des temps de chargement du site car le navigateur client ne peut commencer à télécharger les fichiers du site qu'une fois qu'il a commencé à recevoir la page qui dans son code HTML contient les chemins des autres fichiers à récupérer et comme le PHP ne renvoie la page au serveur Apache qu'une fois celle ci ayant été totalement "générée", si cette dernière est plus longue à générer, le chargement du site en sera d'autant plus longue.


Le cache PHP coté serveur (seulement pour VDS et Dédiés)

Le cache de code machine également appelé cache d'opcodes, il met en cache en mémoire du code PHP pré-calculé en code machine et permet de gagner en temps de calcul et donc de chargement.

Ce type de cache a présenté l'avantage de ne pas nécessiter d'adaptation/configuration spécifique de la part du script PHP exécuté, n'importe quel script PHP est compatible et il ne pose pas de problème avec les contenus dynamiques. Pour utiliser ce type de cache, le PHP doit charger un module adapté, les trois plus courant à l'heure actuellement sont eAccelerator, APC et xCache ; eAccelerator à tendance à ne plus être utilisé car moins maintenu que les deux derniers et généralement moins performant, APC est à peu près aussi efficace que xCache mais possède certaines fonctionnalités en moins (un panneau d'administration permettant de suivre l'utilisation du cache et d'en vérifier le contenu est disponible sous xCache par exemple) mais est par contre disponible depuis plus longtemps (sous Debian 4.0 notamment alors que xCache n'est disponible sous forme de paquet pré-compilé qu'à partir de Debian 5.0). Il est donc possible de les installer en tapant :

apt-get install php5-xcache

Ou :

apt-get install php-apc

(il n'est possible d'utiliser qu'un de ces modules à la fois)

Vous pouvez ensuite adapter la configuration à vos besoins (taille du cache, nombre d'entrées maximales ou encore activer le cache de variables pour xcache par exemple)
Liste des options de configuration pour xCache
Liste des options de configuration pour APC

Compression de données transmises par le serveur Apache (VDS, Dédiés, Permium seulement)

Le module Apache deflate permet de compresser "à la volée" certains fichiers tels que le html, le Javascript ou le CSS. Ce module permet ainsi réduire la quantité de données à charger pour le visiteur du site et est activé par défaut sur mutualisé.

Sur l'installation par défaut d'Apache, le module deflate est installé mais pas forcément actif et sa configuration par défaut ne compresse que les fichiers html, il est possible de l'utiliser aussi pour les fichiers de type CSS et Javascript (qui peuvent à eux seuls faire plusieurs centaines de kilo-octets en fonction des sites), le taux de compression moyen se situe entre 50 et 75% sur ces types de fichiers, ce qui n'est pas négligeable.

Vous pouvez voir quel poids auraient fait les fichiers avec le module activé en utilisant le module Pagespeed pour Firefox (ou sa version pour Google Chrome), en allant dans l'onglet "Pagespeed" puis en cliquant sur "Analyze Performance" dans la rubrique "Enable Compression" et avoir un message tel que :

Compressing the following resources with gzip could reduce their transfer size by 100,1KiB (72% reduction). 

Ce qui veut, dans ce cas dire que la page pourrait passer d'environ 150ko à charger à 50ko avec la compression activée.


Pour activer le module, il suffit depuis un shell de taper la commande :

a2enmod deflate

Pour activer la compression des fichiers autres que html (si ce n'est pas déjà configuré tel quel), il faut modifier le fichier /etc/apache2/mods-available/deflate.conf tel quel :

<IfModule mod_deflate.c>
         # these are known to be safe with MSIE 6
         AddOutputFilterByType DEFLATE text/html text/plain text/xml

         # everything else may cause problems with MSIE 6
         AddOutputFilterByType DEFLATE text/css
         AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
         AddOutputFilterByType DEFLATE application/rss+xml

         BrowserMatch ^Mozilla/4.[0678] no-gzip
         BrowserMatch bMSIEs(7|8|9) !no-gzip !gzip-only-text/html
</IfModule>

(les deux dernières lignes désactivent la compression pour les fichiers autres que html sous ie6 et inférieurs qui peuvent poser problème en affichant parfois des pages blanches)

Il faut ensuite relancer Apache en tapant cette commande :

/etc/init.d/apache2 restart

Vous devriez maintenant, dans "Pagespeed" avoir un check vert à coté de "Compression Enabled" si vous testez un site hébergé sur la machine.