Version complète: sur le forum Webmaster Hub : PHP et cache
Webmaster Hub > Création et exploitation de Sites Internet > Les langages du Net > PHP
MarvinLeRouge
Salut,

Voilà, je voudrais quelques conseils concernant la création d'un système de cache en PHP (je ne compte pas utiliser de systèmes pré-construit car je dois l'utiliser sur un hébergement mutualisé et que je doute des possibilités d'installation) :
Comment faire pour que :
- le serveur gère comme il faut la "if modified since" "last modified" sur une page qui est du php ?
- le serveur compresse les outputs en gz, même lorsqu'il reprend la page en cache ?
- il puisse y avoir des exceptions concernant les pages contenant des formulaires ?

Merci
Kioob
Hello,

j'ai du mal à comprendre exactement ce qui pose soucis dans tes questions, mais je vais tenter de ne pas trop répondre à coté de la plaque biggrin.gif

Déjà il faut bien faire la distinction entre les différents cache. Coté PHP les 3 principaux qu'on croise sont :
- le cache du navigateur (géré à coup de "ETag", de "LastModified" et de "Expires") : cela permet de faire quelques économies de ressource coté serveur et améliore grandement la "sensation de vitesse" pour l'internaute. La page n'est pas re-téléchargée, et généralement pas réinterprétée non plus. Dans le cas de Firefox il peut même être possible de ne pas avoir à ré-exécuter le JS. D'un point de vue utilisateur, c'est pour moi le cache le plus efficace.
- le cache de données (qui consiste à stocker le résultat d'un traitement sous forme "serialisée" ; typiquement une grosse requête). L'avantage c'est qu'il est très souple/modulaire et peut être intégré à tous les types de page de manière plus ou moins complexe. En solution toute prête, il me semble que "Cache_Lite" fait ça.
- le cache de rendu (c'est à dire le code HTML généré par les scripts). C'est de loin le moins souple mais le plus efficace : souvent il se base uniquement sur l'URL pour générer une "clé" et durant N secondes le contenu d'un fichier statique sera directement retourné à l'utilisateur plutôt que d'exécuter les traitements habituels. En solution toute prête, il y aurait JPCache qui faisait ça, et sa soit disant "évolution" QuickCache.

Généralement les caches de rendus se chargent aussi de gérer le cache du navigateur, mais ça n'a rien d'obligatoire. Sur mes sites par exemple je gère systématiquement le cache du navigateur, et sur certains sites/pages j'utilise un cache de données.... mais jamais de cache de rendu par exemple.

Donc toi, tu cherches quelle solution au juste ?


Pour ta première question, il s'agit de gérer correctement le cache navigateur.... et pour les scripts PHP, ça ne se fait pas de manière automatique. C'est donc à tes scripts de prendre ça en charge. Dès lors que tu as la date de dernière modification c'est très simple à mettre en place (ça se fait en 3/4 lignes de code) mais le plus difficile est d'obtenir cette info justement.
Les caches de rendus se basent alors sur l'heure de création du fichier de cache pour gérer le LastModified... et parfois sur le contenu de ce fichier de cache pour générer un checksum et ainsi gérer l'entête ETag.

Pour ce qui est de la compression, elle n'intervient aucunement là dedans... Ormis éventuellement JPCache qui stockait la version compressée de la page afin de ne pas avoir à recompresser systématiquement. Perso je préfère laisser cette tâche à la compression interne de PHP (zlib.output_compression) qui fait ça très bien et sans devoir attendre la fin de la page.

Pour ce qui est des "exceptions", c'est faisable dans tous les cas.
MarvinLeRouge
Alors, je détaille :
  • le site concerné est en php, et le contenu de chaque page est le résultat de requètes base de données pour la récupération du contenu
  • le contenu de chaque page ne change pas trop couramment, c'est pourquoi je souhaite optimiser les traitements côté serveur (interprétation php, requètes sql ...)
  • je voudrais aussi que la page ne soit pas refournie si elle n'a pas changé depuis la dernière visite
  • et qu'elle soit compressée en sortie SI elle doit effectivement être envoyée au client


Sauf erreur de ma part (c'est la première fois que je gère le cache) :
  • pour les 2 premiers points, ça se gère en créant une version "préinterprétée" de la page côté serveur, afin de minimiser les appels réels à la page php. J'avais pensé simplement effacer le fichier de cache concerné lorsqu'un page est modifiée. Ainsi, il devrait la re-créer et la refournir.
  • pour le point "modification depuis la denrière visite", j'ignore comment ça se gère
  • pour le point compression, il faut a priori activer zlib.output_compression, mais est-ce que ça n'a pas un "ordre" d'exécution par rapport à la façon dont le cache serveur agit ?


Merci pour ton aide
Kioob
Ce serait donc un cache de "rendu". Si tu veux le faire toi même, c'est à coup d'ob_start() / ob_get_contents() / file_flush_contents pour l'écriture, puis readfile() pour la lecture. Un simple filemtime() servira à vérifier l'existence et la durée de cache.
Pour le coté "modification depuis la dernière visite", en fait le navigateur envoi le contenu du dernier "LastModified" qu'il a reçu. Il te suffit de comparer cet entête avec la date de ton fichier de cache, et basta.

Pour ce qui est de la compression, il n'y a rien de spécial à faire non... Ormis de penser à la désactiver en cas de réponse 304 (à cause d'un "bug" de PHP).

PS : ça c'est pour la version "full" PHP. L'idéal étant de générer un fichier 100% statique, et de ne faire appel à PHP qu'en cas de d'erreur 404.
MarvinLeRouge
OK, je vais fouiller dans ce sens (et je reviens te poser des questions après biggrin.gif ).

Merci
captain_torche
CITATION(Kioob @ lundi 22 septembre 2008 à 17:48) *
PS : ça c'est pour la version "full" PHP. L'idéal étant de générer un fichier 100% statique, et de ne faire appel à PHP qu'en cas de d'erreur 404.


Lorsque je crée un système de cache, je ne me base pas sur une éventuelle panne du serveur PHP, mais éventuellement de la base SQL (plus fragile à mon goût).
Comment gères-tu une panne d'Apache ? Tu mets tous tes fichiers "cachés" à la racine ?
Kioob
Là j'avoue que je ne vois pas du tout ce que tu veux dire.

Le principe est le suivant : imaginons que l'internaute demande au serveur la page /bidule/truc.html .
Tu as deux cas :
- elle n'existe pas : le serveur déclenche une erreur 404, et par configuration tu peux lui demander d'appeler un script PHP. Si ce script PHP estime que "bidule/truc.html" correspond effectivement à un contenu, il va créer le fichier /bidule/truc.html et retourner un code 200 ainsi que le contenu de ce fichier.
- elle existe : le serveur retourne directement cette page, tout en gérant comme il se doit les divers entêtes HTTP et la compression à la volée.

C'est plus complexe à mettre en place, n'est vraiment pas adapté aux sites très dynamiques de type forum ou personnalisés en fonction de l'utilisateur, mais le gain de performances n'a vraiment rien à voir avec ce qu'on peut obtenir en se basant uniquement sur PHP.

Mais le but ici est clairement les performances, pas de contourner un problème Apache, PHP ou encore MySQL.

Pour masquer les problèmes de MySQL, j'utilise un simple cache de données.
Pour contourner les problèmes de PHP, j'ai FCGID qui envoi une page 500 personnalisée.
Pour contourner les problèmes d'Apache, j'ai NginX en front qui envoi une page 503 personnalisée.
captain_torche
En fait, ce que je fais est sensiblement différent :
- via htaccess, je détourne toute demande de fichier .html vers une page de traitement.
- cette page vérifie la présence du fichier dans mon répertoire cache, et sa date. Si le fichier n'existe pas ou est trop vieux, on le regénère et on le crée. S'il existe, on se contente de l'afficher.
Kioob
Oui donc méthode "classique" (que j'utilise également hein), le soucis étant que dans ces cas là tu utilises PHP "pour rien".... et justement c'est très lent.
Essaye de faire un simple benchmark sur un fichier HTML statique puis sur un fichier PHP contenant uniquement ce code HTML (sans le moindre tag PHP) ; la différence est énorme.
captain_torche
Si lenteur il y a, elle n'est pas visible par l'internaute, en tout cas. Et c'est tout ce qui compte wink.gif
Kioob
Ca, ça dépend de la taille du site... arrivé à un certain trafic, quand on loue déjà plusieurs serveurs à 500€ HT/mois chez OVH, il faut commencer à se poser ce genre de questions biggrin.gif

Il est évidement que si un "SP Mini" suffit pour le site, ce n'est pas non plus la peine de se prendre le chou avec des techniques "complexes".
captain_torche
C'est pour le boulot, donc je pense que le serveur est correctement dimensionné (même si je n'en connais pas les spécifications).
Les sites génèrent entre 2 et 4 000 visiteurs/jours, et contiennent une bonne dizaine de milliers de pages.
ams51
CITATION(Kioob @ dimanche 21 septembre 2008 à 21:43) *
- le cache de rendu (c'est à dire le code HTML généré par les scripts). C'est de loin le moins souple mais le plus efficace : souvent il se base uniquement sur l'URL pour générer une "clé" et durant N secondes le contenu d'un fichier statique sera directement retourné à l'utilisateur plutôt que d'exécuter les traitements habituels.


J'avais mis en place une technique simple de cache de rendu à base de

CITATION(Kioob @ lundi 22 septembre 2008 à 17:48) *
Si tu veux le faire toi même, c'est à coup d'ob_start() / ob_get_contents() / file_flush_contents pour l'écriture, puis readfile() pour la lecture. Un simple filemtime() servira à vérifier l'existence et la durée de cache.


Plus simple que ça tu meurs... sauf qu'au moment des pics de fréquentation la charge serveur a tendance à s'emballer et le serveur à swapper sur le disque...
Le remède a été bien pire que le mal.
Kioob
Avec 4'000 vu par jour, c'est clair qu'on a pas à se poser ce genre de questions... Mais avec 400'000 ça peut.

ams51 : yep c'est bien pour ça que je n'utilise pas de cache de rendu. J'ai un client qui avait pas loin de 20Go de fichiers servant à son cache de rendu... le serveur passe plus de temps à écrire sur le disque qu'autre chose.
Ceci est une version "bas débit" de notre forum. Pour voir la version complète avec plus d'information, la mise en page et les images, veuillez cliquer ici.