Il existe plusieurs façons d’améliorer les performances du site, 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.
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 les outils pour développeur intégrés dans les navigateurs modernes. 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 activé par défaut sur mutualisé permet ainsi réduire la quantité de données à charger pour le visiteur du site.
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, 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.