php-experts.org - développement php et internet » optimisation https://www.php-experts.org Ressources sur le développement internet, PHP/MySQL, Ajax, marketing online, référencement... Sat, 19 Jun 2010 14:23:03 +0000 http://wordpress.org/?v=2.9.2 en hourly 1 Cache d’opcode: Alternative Php Cache (APC) https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62 https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62#comments Tue, 09 Dec 2008 17:23:58 +0000 Didier https://www.php-experts.org/?p=62 Pour accélerer les performances d’un site internet, il existe de nombreuses pistes à suivre. Outre les recommandations d’optimisation de Yahoo, qui concernent surtout l’architecture d’une application Web, on peut aussi s’attaquer à des couches plus transparentes (et souvent complètement ignorées par les développeurs), comme l’étape de “compilation” du script en exécutable. Nous allons voir comment APC (Alternative Php Cache) peut nous aider rapidement à accélérer des scripts php.

L’opcode ?

Oui, l’opcode. C’est le code généré par votre serveur Web (qui a dit Apache ?) à partir de vos scripts PHP, après leur interprétation et leur compilation. Ce code est exécutable, et sa génération prend un certain temps. A chaque exécution d’un script, le serveur régénère cet opcode, perdant ainsi un temps précieux: quand votre script n’a pas été modifié, cette étape est totalement inutile. On peut l’éviter en mémorisant l’opcode grâce à un cache d’opcode
Attention, il ne faut pas confondre les caches d’opcode et les caches HTML: un cache HTML servira à envoyer directement la sortie d’un script au client, sans traitement. Le cache d’opcode, lui, laisse place à l’exécution proprement dite du script dans des conditions normales: les données provenant d’une base de données MySQL, par exemple, seront rapatriées comme à l’accoutumée. On ne perd donc aucune réactivité au niveau de l’application, tout en améliorant ses temps de réponse.

APC ? (Alternative Php Cache)

Oui, APC. APC est un projet libre, implémenté comme une extension Zend. Cela permet de le compiler dans PHP ou de l’intégrer plus tard, comme un module classique. Le principal avantage d’APC (et des autres caches d’opcode) est qu’il n’y a aucun besoin en terme de modification des scripts: il suffit d’installer et d’activer le module pour que celui-ci accélère vos scripts PHP. De ce côté là, donc, rien de spécial à ajouter.
APC permet, par un script d’administration, de suivre quels opcodes sont mis en cache, le nombre de hits économisés, ainsi que les données utilisateur. Très pratique, la colonne “miss” vous indique combien de scripts ont été appelés sans profiter de l’accélération d’APC (Cela peut arriver car vous pouvez mettre des filtres en place pour ne stocker que certains répertoires, ou limiter la taille en mémoire occupée par l’ensemble des scripts “compilés”, par exemple…)

Le cache de données utilisateur

Mais là où réside, selon moi, la vraie puissance d’APC, est dans son cache de données utilisateur. En effet, imaginons le cas où nous avons une requête SQL assez lourde, suivie d’un traitement assez conséquent: sur la page d’accueil d’un forum (lien-copinage), on souhaite afficher les derniers connectés et le nombre de messages qu’ils ont posté. En théorie, à chaque affichage de la page, on va réexécuter la requête, et donc assassiner bêtement le serveur SQL.
On pourrait stocker les données dans une Session PHP ? Oui, mais d’une, les sessions ne sont pas faites pour ça, et de deux, on exécuterait quand même la requête SQL et le traitement associé pour chaque nouveau connecté.
La meilleure solution reste alors d’utiliser le cache de données d’APC. On va pour cela se servir de la fonction apc_store, qui prend 3 paramètres :
bool apc_store ( string $key , mixed $var [, int $ttl ] )

  • $key est le nom que l’on souhaite donner à la variable dans le “magasin” (store) d’APC. Je vous conseille de la préfixer du nom du site concerné si vous hébergez plusieurs sites sur le même serveur ; les variables sont accessibles à tous les scripts (attention donc à ce que vous faites dans le cas d’un hébergement partagé… ne stockez de préférence aucune donnée “sensible” à moins de savoir précisément ce que vous faites).
  • $var est la valeur à stocker, qui peut être un nombre, une chaîne, un tableau, ou même un objet complet (Attention, dans ce dernier cas, à bien inclure la déclaration de classe de l’objet avant d’essayer de le récupérer…).
  • $ttl est le “Time To Live” de la variable, c’est à dire le temps en secondes avant qu’APC ne l’efface de son store.

Par exemple, dans le cadre de notre forum, on aurait quelque chose comme :

  1. apc_store(‘forum_derniers_connectes’,$derniersConnectes,60);

Ce qui signifie qu’on stocke, tel quel, le tableau (array) $dernierConnectes, sous le nom forum_derniers_connectes, pour une durée de 60 secondes.

Pour accéder à la variable, on dispose de la fonction apc_fetch, qui prend le $key de la variable en paramètre, et renvoie soit la valeur stockée, soit FALSE en cas d’échec. On peut donc faire :

  1. if (!$derniersConnectes = apc_fetch(‘forum_derniers_connectes’)) {
  2. // forum_derniers_connectes n’est pas présent dans le cache: il faut le calculer
  3. $derniersConnectes = get_derniers_connectes(); // boum, on exécute
  4. apc_store(‘forum_derniers_connectes’,$derniersConnectes,60);
  5. }

C’est tout ! Si APC trouve la variable, il renseigne $derniersConnectes. Dans le cas contraire, on rapatrie les infos et on les stocke pour 60 secondes. La requête-de-la-mort ne sera plus exécutée qu’une fois par minute.

Bénéfices

Le bénéfice est donc double: on économise à la fois sur le temps d’exécution des scripts en ne les compilant qu’au besoin grâce au cache d’opcode (d’environ 50% selon les auteurs, sachant que cela dépendra de la complexité du script… on gagnera beaucoup plus sur des algorithmes récursifs, notamment), mais aussi sur le temps de processing de certaines ressources grâce au cache de données, qui est utilisé ici pour des requêtes SQL mais qui pourrait aussi bien l’être pour la lecture du fichier de configuration de votre application, par exemple (en stockant, au choix, un tableau associatif ou un objet $config), ou de n’importe quelle variable qui n’a pas vraiment besoin d’être mise à jour en temps réel.

Liens utiles

Manuel APC sur php.net (en français)

]]>
https://www.php-experts.org/developpement-web/php-developpement-web/cache-dopcode-alternative-php-cache-apc-62/feed 0
Optimisation d’une requête SQL avec EXPLAIN et log_slow_queries https://www.php-experts.org/bases-de-donnees/mysql/autopsie-et-optimisation-dune-requete-sql-avec-explain-et-log_slow_queries-14 https://www.php-experts.org/bases-de-donnees/mysql/autopsie-et-optimisation-dune-requete-sql-avec-explain-et-log_slow_queries-14#comments Sat, 12 Jul 2008 17:22:34 +0000 Didier https://www.php-experts.org/?p=14 Depuis quelques temps, un serveur qui héberge quelques petits sites s’est mis à monter régulièrement en charge, sans augmentation de trafic, ni changements applicatifs. J’ai laissé traîner les choses, ne sachant pas d’où venait le souci.
Il aura fallu cinq minutes de travail et l’utilisation de la commande shell top, de la directive de configuration MySQL log_slow_queries et de la commande SQL EXPLAIN pour régler le problème de lenteur des sites.
Tout d’abord, un top a confirmé mes craintes : c’est bien le serveur MySQL qui était en cause, prenait beaucoup de mémoire RAM et de ressources processeur. Il y avait donc des requêtes SQL qui avaient besoin d’être optimisées.

J’ai édité le fichier de configuration de MySQL (/etc/mysql/my.cnf sous Linux Debian) pour y activer l’option log-slow-queries en modifiant les trois lignes suivantes :

  1. log_slow_queries = /var/log/mysql/mysql-slow.log
  2. long_query_time = 2
  3. log-queries-not-using-indexes

Je le répète, long_query_time = 2 signifie qu’on doit logger toutes les requêtes qui mettent plus de deux secondes à s’exécuter. Après un redémarrage du serveur (cette option ne peut malheureusement pas être changée à chaud), j’ai attendu la montée en charge suivante pour que MySQL (grâce à long_query_time) enregistre sagement toutes les requêtes mettant plus de 2 secondes à s’exécuter (log_query_time est exprimé en secondes et doit être un nombre entier compris entre 1 et 10), et celles qui n’utilisaient aucun index, dans le fichier /var/log/mysql-slow.log

Voici ce que j’y ai trouvé :

  1. # Query_time: 0  Lock_time: 0  Rows_sent: 5  Rows_examined: 17165
  2. SELECT * FROM chanson LEFT JOIN artiste ON artiste_ID = ID_artiste WHERE artiste_ID = 50 ORDER BY RAND() LIMIT 5;

Quasiment 20.000 lignes examinées (la totalité de la table) pour une requête qui en ramènera seulement 5, c’est beaucoup.

Je me suis connecté à phpMyAdmin, et j’ai utilisé la commande explain, en rajoutant simplement le mot EXPLAIN devant ma requête SQL :

  1. EXPLAIN SELECT *
  2. FROM chanson
  3. LEFT JOIN artiste ON artiste_ID = ID_artiste
  4. WHERE artiste_ID = 50
  5. ORDER BY RAND( )
  6. LIMIT 5;

La commande MySQL EXPLAIN permet de voir, notamment, les clés (index, primary, uniques…) utilisées pour aller chercher les résultats d’une requête, ainsi que le nombre de lignes parcourues.
Voici quel a été le résultat de la commande Explain :
MySQL Explain

J’ai ajouté un “ID_artiste = 50″ dans la clause WHERE, qui n’a rien changé. Explain renvoyait toujours “NULL” dans les Possible keys concernant la table Chanson. Après vérification, en effet, il n’y avait aucun index sur ce champ de la table, pourtant souvent utilisé dans mes clauses WHERE. Un ALTER TABLE `chanson` ADD INDEX(`artiste_ID`) plus tard, la création de l’index sur le champ de la base de données concernée a permis de changer le résultat de l’EXPLAIN sur la même requête SQL :
MySQL Explain
Plus que 76 lignes lues pour renvoyer la réponse, la requête n’apparaitra très certainement plus dans le slow_query_log.

En recommençant l’opération (toujours avec Explain) sur toutes les requêtes qui se trouvaient dans le fichier de log, j’ai trouvé plusieurs points à améliorer pour accroître les performances du serveur MySQL. Finis, les problèmes de montée en charge !

Pour en savoir plus :
Documentation officielle MySQL de la syntaxe de EXPLAIN

]]>
https://www.php-experts.org/bases-de-donnees/mysql/autopsie-et-optimisation-dune-requete-sql-avec-explain-et-log_slow_queries-14/feed 3
Yahoo vous aide à accélérer votre site internet https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8 https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8#comments Mon, 30 Jun 2008 10:20:18 +0000 Didier https://www.php-experts.org/?p=8 Après avoir publié ses “Best Practices for Speeding Up Your Web Site” (comprendre: meilleures pratiques pour accélérer votre site internet”, Yahoo met désormais à disposition des développeurs YSlow!, une extension pour FireBug, célèbre plug-in Firefox, qui permet de faire un rapport d’optimisation pour la vitesse du site que vous visitez.

Le plug-in, très simple d’utilisation (un click dans la barre d’état lance l’analyse, qui apparait dans le panneau FireBug), recense toutes les modifications que vous pouvez apporter pour atteindre le fameux Speed Rank A, réservé à l’élite des sites rapides… (disons que les 34 critères définissent le « site rapide théorique parfait », mais ne sont pas tous applicables dans le monde réel. Par exemple, Yahoo recommande d’utiliser un CDN (Content Delivery Network), solution généralement assez chère pour ne pas être déployable sur des sites à moyen traffic et peu monétisés.

Voici un rappel de ce qu’il faut faire et éviter, aux yeux de Yahoo.


Les critères ont été classés en 7 catégories :

  1. Le contenu
  2. Le serveur
  3. Les cookies
  4. Les CSS (Cascading Style Sheets… les feuilles de style, quoi)
  5. Le Javascript
  6. Les images
  7. Version « mobile »

Tour d’horizon des critères que je trouve utiles parmi les 34 proposés :

Faire le moins de requêtes HTTP possible

Partant du principe que 80% du temps de rendu d’une page consiste en téléchargement (vu la source des données –Yahoo- je pense qu’on peut considérer ce chiffre comme fiable), Yahoo recommande clairement de « combiner » les fichiers : regroupez toutes vos classes CSS dans un seul fichier, toutes les fonctions Javascript dans un autre. A noter que, même si personnellement, je ne suis pas fan de la méthode, cela permet de maximiser l’effet des caches navigateur. Au premier chargement d’une page de votre site, l’utilisateur dispose de tous les éléments dont il aura besoin au fil de la navigation. On gagne donc pas mal de temps (et de bande passante) pour toutes les autres pages qu’il verra.

Dans la même optique, Yahoo recommande d’utiliser des « CSS Sprites » pour afficher les images (coins arrondis et compagnie) et des « Images Map », ce qui réduit le nombre de fichiers à télécharger.

Jouer avec les sous-domaines, mais en réduisant les DNS Lookups

Les navigateurs internet comme Internet Explorer ou Firefox, quand ils récupèrent les éléments d’une page, ne peuvent faire que deux téléchargements simultanés par nom de domaine. En gros, si vous mettez vos pages statiques (donc, le HTML) sur www.domain.tld, vos images sur img.domain.tld et vos feuilles de styles et javascripts sur elements.domain.tld, vous accélèrerez le téléchargement total de la page en multipliant les requêtes simultanées.

Attention, les DNS Lookups nécessaires pour récupérer l’adresse IP des sous-domaines prend du temps, donc n’en abusez pas. Yahoo considère que 2 à 4 sous-domaines est une fourchette acceptable.

Utiliser un Content Delivery Network ou CDN

Alors là, rien à redire : il est parfaitement logique qu’un CDN accélère votre site. C’est le but. Les Content Delivery Networks sont, en gros, des réseaux de serveurs qui vont « capturer » votre contenu statique (Javascript, CSS, images, mais aussi HTML) et le servir à votre place. Parmi les plus connus, Akamai comprend 20000 serveurs répartis dans 71 pays (données corporate). En effet, difficile de rivaliser ;)

Ajouter des headers « Expires » ou « Cache-control »

Là, deux cas :

  • Soit on parle de contenu statique et on peut utiliser un Expires, qui indique au navigateur quand est-ce qu’il devra recharger le composant au lieu de le piocher dans son cache,
  • Soit on parle de contenu dynamique, et on devra plutôt se servir de Cache-Control pour définir le comportement à adopter.

Le header « Expires » sert à spécifier au browser une date d’expiration pour le document visé. En gros, si j’ajoute à ma feuille de style un “Expires: Thu, 15 Apr 2010 20:00:00 GMT”, votre navigateur n’essaiera même pas de la télécharger avant cette date.

Bonne idée de Yahoo : utiliser une norme de nommage des fichiers qui consiste à suffixer le nom par le numéro de version (comme dans « yahoo_2.0.6.js ») : cela permet d’être sur que le fichier ne sera jamais modifié (sauf en cas de changement de version, où il sera renommé), et donc d’utiliser le plus souvent un Expires : aucun travail pour le serveur quand le document est déjà dans le cache du navigateur.

GZipper votre contenu

En compressant ce qui sort de votre serveur, vous améliorez le temps de chargement des éléments (logique). Il faut prendre en compte l’impact que la compression peut avoir sur les performances de votre site : le processeur de votre serveur sera plus sollicité, mais vous économiserez de la bande passante.

La plupart des clients qui suivent la norme HTTP/1.1 envoient un header « Accept-Encoding : gzip, deflate » auquel le serveur, s’il le peut, répondra par du contenu zippé avec un header « Content-Encoding : gzip ».

Pour que cela soit le cas, avec Apache 1.3, il faut installer et activer mod_gzip, remplacé pour Apache2 par mod_deflate.

Feuilles de style en haut et javascripts en bas, flush() fréquents

En embarquant vos feuilles de style dès le tag <head> de votre page, vous permettez au navigateur du client d’afficher celle-ci de manière progressive au cours de son chargement. Même si techniquement, cela ne change en rien la vitesse de chargement, l’impact psychologique de voir la page de remplir est tel qu’on a une impression de vitesse. Vous pouvez lire l’étude UseIt sur le “progressive rendering. Dans la même idée, utiliser un flush() après votre header (fonction qui ordonne au serveur d’envoyer le HTML déjà généré sans attendre la fin de la création de la page) permettra à la page de s’afficher plus rapidement, puisque les téléchargements connexes pourront commencer avant que le serveur n’aie fini ses calculs.

Selon la norme HTTP/1.1, les navigateurs ne doivent télécharger que deux éléments en parallèle par hostname. Si vous placez vos Javascripts en haut de votre code-source, le navigateur les téléchargera et donc bloquera l’un des deux téléchargements pour eux, qui n’ont pas d’impact visuel. A choisir, mettez les donc vers le bas du document, après que la structure de la page, les feuilles de styles et les images aient été chargées.

Minifier le code Javascript et les CSS (feuilles de style)

Minifier le code revient à en enlever les espaces inutiles, tabulations, retours à la ligne… On se retrouve avec une bouillie illisible mais beaucoup plus rapidement chargée qu’un code propre et indenté. Regardez le code-source de la home de Google… Il faudra bien évidemment garder une version « non-minifiée » de vos scripts, pour pouvoir les retoucher en cas de besoin. Yahoo propose 2 outils de minification : JsMin et YUI Compressor. J’en ai développé un aussi, mais je pense que le leur marchera mieux ;)

Gérer intelligemment les tailles d’images

Il ne faut jamais utiliser une image carrée de 500px de côté avec un width= »100 » pour la redimensionner en HTML. Le navigateur devra toujours télécharger l’image dans sa taille originale. Faites une copie plus petite de l’image !

Pensez à ajouter une favicon à votre site. Dans tous les cas, les navigateurs la demandent, et auront donc à télécharger votre page d’erreur 404 personnalisée (vous en avez une, n’est ce pas ? … Yahoo recommande d’éviter pour ne pas gaspiller de ressources serveur, mais Yahoo n’est pas référenceur…) en lieu et place de la petite icône qui apparaitra dans les favoris de vos utilisateurs et dans les onglets de leur navigateur. Même combat pour le robots.txt : il sera de toute façon demandé, donc autant en avoir un.

D’après Yahoo, le meilleur format d’images actuel est PNG (« Give PiNG a Chance », qu’ils disaient…) : tout ce qu’un GIF peut faire, un PNG8 peut le faire aussi, pour une taille de fichier souvent moindre. A essayer :)

Voici une rapide présentation des points qui m’ont semblés être des “quick-win” dans ce que propose Yahoo. La liste est loin d’être exhaustive, j’ai volontairement “oublié” des items de la liste qui avaient l’air moins importants (ou plus complexes à mettre en place) pour un site de taille raisonnable.

Un peu de lecture pour aller plus loin :

Et vous, quelles sont vos habitudes ?

]]>
https://www.php-experts.org/developpement-web/yahoo-vous-aide-a-accelerer-votre-site-internet-8/feed 10