darma | développement web freelance

Tips & Codes sources

«the First-click Suspense», part 3

Report de scripts, crons et calculs offline

Le bon script au bon moment

La partie précédente de cet article (Part 2 : Un cache serveur HTML et PHP pour les sites éditoriaux) montre comment bénéficier facilement d'une économie conséquente de calculs serveur (requêtes SQL et évaluation de PHP) pour des sites basés sur PHP + MySQL. Ce procédé est un excellent exemple de "bon calcul au bon moment", à savoir la génération et mise en cache d'une page web au moment où elle est périmée, et non pas à chaque fois qu'elle est demandée par un visiteur. Il existe dans cette lignée d'autres méthodes et habitudes permettant d'optimiser les ressources serveur, correspondant pour la plupart elles aussi à d'autres types de mises en cache (de données ou de fichiers) :

Reporter les scripts sur le back-office

On suppose ici qu'on utilise un back-office capable de déclencher des évènements de manière fine sur éléments modifiés : typiquement, si tel champ de tel enregistrement de telle table est modifié, on veut pouvoir appliquer tel calcul qui n'a logiquement lieu d'être qu'à cette occasion - exemples :
  • On utilise de l'URL rewriting sur le front-office et l'URL de chaque page est issue d'une requête SQL sur plusieurs tables (l'URL devra contenir par exemple le titre, le nom d'auteur et le thème d'un article) - l'URL est de plus "nettoyée" de ses caractères spéciaux par un script PHP : au lieu de générer cette URL à chaque fois que l'on veut l'afficher sur le front, et également pour garantir son unicité dans tout le site, on crée un champ "url" dans la table "article" qui sera modifié lorsque et uniquement si un champ l'affectant est modifié en back-office.
  • On veut afficher un nuage de tags correspondant à une rubrique d'articles et leurs tags associés : ce nuage (son rendu HTML) pourra être mis en base lors de l'attribution des tags en back-office.

Mettre des données en cache sur input visiteur

Le principe précédent est aussi valable en front-office, où l'on peut vouloir stocker des données dont on sait précisément à quel moment les mettre à jour :
  • On propose aux visiteurs d'ajouter des reviews (ou commentaires) à des produits, et l'on veut afficher dans des listes le nombre total de ces reviews pour chaque produit : la table "produit" contiendra un champ "nb_reviews" mis à jour à chaque nouvelle insertion de review.
  • De manière similaire, on propose aux visiteurs de noter des produits, et l'on veut afficher dans des listes la note moyenne attribuée à chaque produit : la table "produit" contiendra un champ "note_moyenne" mis à jour à chaque nouvelle insertion de note.
  • Sur un site où chaque utilisateur possède sa propre page de profil, on pourra stocker le contenu central de cette page (en base ou en fichier) à chaque modification (par l'utilisateur lui-même ou à l'ajout de commentaires sur son profil, etc.).

Crons et calculs offline

Les crons définissent sous Unix des tâches planifiées dont on détermine à l'avance l'heure et le cycle d'exécution. Elles permettent donc de mettre en place des scripts PHP exécutés à intervalles réguliers.
Leur première utilisation évidente consiste à y placer du code que l'on veut réellement exécuter toutes les X minutes ou heures, ni plus ni moins :
  • effectuer un back-up de base de données toutes les 24h.
  • envoyer un mailing toutes les semaines.
  • etc.
Mais les crons peuvent également être utilisées pour mettre en cache des données lourdes à récupérer (provenant par exemple de sites externes ou web services), ou plus généralement pour effectuer des calculs dans un écosystème complexe, calculs qui demanderaient à être effectués trop souvent s'ils se voulaient d'une justesse permanente et pour lesquels on peut se permettre un certain temps de latence :
  • récupérer un flux RSS sur un site externe, le formater et le stocker localement sous la forme directement nécessaire à l'affichage sur notre site.
  • générer des flux RSS internes (avec d'autant d'importance que ces fichiers sont demandés de manière régulière et automatique au serveur par les abonnés et peuvent proportionnellement constituer un nombre important de requêtes).
  • générer un fichier sitemap.xml destiné aux robots d'indéxation des moteurs de recherche.
  • mettre à jour des indexes FULLTEXT pour une recherche interne à notre site.
  • calculer des matrices de similarités entre produits pour proposer des recommandations personnalisées (ou l'équivalent pour des articles et proposer des articles similaires type "voir aussi").
  • générer des scores utilisateurs et des images (composées de calques PNG) calculées à la GD.

Les caches d'images

La plupart des images apparaissant sur un site sont présentes en plusieurs versions, image principale et vignettes. Il est bien entendu déconseillé (interdit?) de fixer leur taille à l'aide des attributs width et height du tag img : les images plus grandes que nécessaire occuperont bande passante et durée de chargement, celles plus petites auront un rendu médiocre. On peut de plus vouloir recadrer notre image différemment suivant son emplacement : resize, crop, etc.
On génère donc généralement ces différentes versions d'une image à l'aide d'une librairie graphique PHP (GD), soit au moment de l'upload en back-office, soit "à la demande" à l'aide d'un système de cache d'images :
Ce système sera composé d'un script PHP prenant en GET les paramètres nécessaires (identifiant de l'image originale, largeur et hauteur, crop ou non, etc.), générant l'image correspondante et l'enregistrant localement (si encore non existante) et la renvoyant au navigateur à l'aide de l'en-tête approprié (ex : header('Content-Type: image/jpeg');).
Un script similaire pourra exister afin de gérer d'éventuelles images-titres dynamiques nécessaires à un design utilisant des fonts hors "websafe".

Scripts aléatoires

Dernière technique exposée ici, utile lorsque l'on veut exécuter un script régulièrement mais pas à chaque affichage de page, et lorsque l'on bénéficie d'un trafic assez important pour que cette notion de régularité devienne statistique :
Utiliser la fonction rand de PHP (dans cet exemple on aura statistiquement une chance sur 100 d'exécuter le script) :
<?php
if(rand(0,100) == 50){
    //script à exécuter
}
?>
Cette méthode est utile lorsque l'on ne peut pas ou ne souhaite pas mettre le script en cron, et lorsque celui-ci prend de l'intérêt non pas relativement à une durée mais à une récurrence de visites.