web-dev-qa-db-fra.com

En cache, PHP Les vignettes générées se chargent lentement

Question Partie A ▉ (100 primes, accordées)
La question principale était de savoir comment rendre ce site plus rapide à charger. Nous devions d'abord lire ces cascades. Merci à tous pour vos suggestions sur l'analyse de la lecture de la cascade. Les principaux graphiques illustrant les cascades sont mis en évidence par le principal goulot d'étranglement: les miniatures générées par PHP. Le chargement jquery sans protocole à partir de CDN conseillé par David a obtenu ma prime, bien que cela rende mon site seulement 3% plus rapide dans l'ensemble, et sans répondre au principal goulot d'étranglement du site. Il est temps de clarifier ma question et, une autre prime:

Question Partie B ▉ (100 primes, accordées)
Le nouvel objectif était maintenant de résoudre le problème des 6 images jpg, qui causent le plus de retard de chargement. Ces 6 images sont des miniatures générées par PHP, minuscules et seulement 3 ~ 5 ko, mais se chargeant relativement très lentement. Notez le " temps pour le premier octet" sur les différents graphiques. Le problème est resté non résolu, mais une prime est allée à James, qui a corrigé l'erreur d'en-tête que RedBot souligné : "Une demande conditionnelle If-Modified-Since a renvoyé le contenu complet inchangé.".

Question Partie C ▉ (ma dernière prime: 250 points)
Malheureusement, même après que l'erreur d'en-tête REdbot.org a été corrigée, le retard causé par les images générées par PHP est resté intact. Que diable pensent ces minuscules miniatures minuscules de 3 à 5 Ko? Toutes ces informations d'en-tête peuvent envoyer une fusée sur la lune et en revenir. Toutes les suggestions sur ce goulot d'étranglement sont très appréciées et traitées comme une réponse possible, car je suis coincé à ce problème de goulot d'étranglement depuis déjà sept mois maintenant. Merci d'avance.

[Quelques informations de fond sur mon site: CSS est en haut. JS en bas (Jquery, JQuery UI, acheté les moteurs de menu awm/menu.js, les onglets js engine, video swfobject.js) Les lignes noires sur la deuxième image montrent ce qui initie quoi charger. Le robot en colère est mon animal de compagnie "ZAM". Il est inoffensif et souvent plus heureux.]


Cascade de charge: chronologique | http://webpagetest.org enter image description here


Domaines parallèles groupés | http://webpagetest.org enter image description here


Cascade Site-Perf | http://site-perf.com enter image description here


Pingdom Tools Waterfall | http://tools.pingdom.com

enter image description here


Cascade GTmetrix | http://gtmetrix.com

enter image description here


179
Sam

Tout d'abord, l'utilisation de ces multiples domaines nécessite plusieurs recherches DNS. Vous feriez mieux en combinant plusieurs de ces images dans un Sprite au lieu de diffuser les demandes.

Deuxièmement, lorsque je charge votre page, je vois la plupart des blocages (~ 1,25 s) sur all.js. Je vois que cela commence par (une ancienne version de) jQuery. Vous devez référencer cela à partir du CDN Google, non seulement réduire le temps de chargement , mais potentiellement éviter une demande HTTP pour cela entièrement.

Plus précisément, les bibliothèques jQuery et jQuery UI les plus récentes peuvent être référencées à ces URL (voir cet article si vous êtes intéressé pourquoi j'ai omis le http:):

//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js

//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js

Si vous utilisez l'un des thèmes d'interface utilisateur jQuery par défaut, vous pouvez également retirer son CSS et ses images du Google CDN .

Avec l'hébergement jQuery optimisé, vous devez également combiner awmlib2.js et tooltiplib.js dans un seul fichier.

Si vous abordez ces points, vous devriez voir une amélioration significative.

61
Dave Ward

J'ai eu un problème similaire il y a quelques jours et j'ai trouvé head.js . C'est un plugin Javascript qui vous permet de charger tous les fichiers JS en parallèle. J'espère que cela pourra aider.

17
000

Je suis loin d'être un expert mais ...

En ce qui concerne ceci: "Une demande conditionnelle If-Modified-Since a renvoyé le contenu complet inchangé." et mes commentaires.

Le code utilisé pour générer les vignettes doit vérifier les éléments suivants:

  1. Existe-t-il une version en cache de la miniature.
  2. La version mise en cache est-elle plus récente que l'image d'origine.

Si l'un ou l'autre est faux, la vignette doit être générée et retournée quoi qu'il arrive. S'ils sont tous les deux vrais, la vérification suivante doit être effectuée:

  1. Existe-t-il un en-tête HTTP_IF_MODIFIED_SINCE
  2. La dernière heure de modification de la version mise en cache est-elle la même que HTTP_IF_MODIFIED_SINCE

Si l'un ou l'autre est faux, la vignette mise en cache doit être retournée.

Si les deux sont vraies, un état 304 304 doit être renvoyé. Je ne sais pas si c'est nécessaire, mais je renvoie également personnellement les en-têtes Cache-Control, Expires et Last-Modified avec le 304.

En ce qui concerne GZipping, j'ai été informé qu'il n'y a pas besoin d'images GZip, alors ignorez cette partie de mon commentaire.

Edit: je n'ai pas remarqué votre ajout à votre message.

session_cache_limiter('public');
header("Content-type: " . $this->_mime);
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 2419200) . " GMT");
// I'm sure Last-Modified should be a static value. not dynamic as you have it here.
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time() - 404800000) . " GMT");

Je suis également sûr que votre code doit vérifier l'en-tête HTTP_IF_MODIFIED_SINCE et y réagir. La définition de ces en-têtes et de votre fichier .htaccess ne fournira pas le résultat requis.

Je pense que vous avez besoin de quelque chose comme ça:

$date = 'D, d M Y H:i:s T'; // DATE_RFC850
$modified = filemtime($filename);
$expires = strtotime('1 year'); // 1 Year

header(sprintf('Cache-Control: %s, max-age=%s', 'public', $expires - time()));
header(sprintf('Expires: %s', date($date, $expires)));
header(sprintf('Last-Modified: %s', date($date, $modified)));
header(sprintf('Content-Type: %s', $mime));

if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified) {
        header('HTTP/1.1 304 Not Modified', true, 304);
        // Should have been an exit not a return. After sending the not modified http
        // code, the script should end and return no content.
        exit();
    }
}
// Render image data
12
James

Wow, c'est difficile d'expliquer les choses en utilisant cette image .. Mais ici, quelques essais:

  • les fichiers 33-36 se chargent si tard, car ils sont chargés dynamiquement dans le swf, et le swf (25) est d'abord chargé complètement avant de charger tout contenu supplémentaire
  • les fichiers 20 et 21 sont peut-être (je ne sais pas, parce que je ne connais pas votre code) des bibliothèques qui sont chargées par all.js (11), mais pour que 11 s'exécute, il attend la page entière (et les ressources) à charger (vous devez la remplacer par domready)
  • les fichiers 22-32 sont chargés par ces deux bibliothèques, encore une fois après qu'elles soient complètement chargées
6
poke

J'ai trouvé l'URL de votre site Web et vérifié un fichier jpg individuel à partir de la page d'accueil. Bien que le temps de chargement soit raisonnable maintenant (161 ms), il attend 126 ms, ce qui est beaucoup trop.

Vos en-têtes modifiés en dernier sont tous définis sur Sam, 01 Jan 2011 12:00:00 GMT, ce qui semble trop "rond" pour être la vraie date de génération ;-)

Étant donné que le contrôle du cache est "public, max-age = 14515200", les en-têtes de dernière modification arbitraires pourraient poser problème après 168 jours.

Quoi qu'il en soit, ce n'est pas la vraie raison des retards.

Vous devez vérifier ce que fait votre générateur de vignettes lorsque la vignette existe déjà et ce qui pourrait prendre autant de temps à vérifier et à fournir l'image.

Vous pouvez installer xdebug pour profiler le script et voir où se trouvent les goulots d'étranglement.

Peut-être que le tout utilise un framework ou se connecte à une base de données pour rien. J'ai vu très lentement mysql_connect () sur certains serveurs, principalement parce qu'ils se connectaient en utilisant TCP et non socket), parfois avec quelques problèmes DNS.

Je comprends que vous ne pouvez pas publier votre générateur rémunéré ici, mais je crains qu'il y ait trop de problèmes possibles ...

4
Capsule

S'il n'y a pas vraiment de bonne raison (généralement il n'y en a pas), vos images ne doivent pas invoquer l'interpréteur PHP.

Créez une règle de réécriture pour votre serveur Web qui gère directement l'image si elle se trouve sur le système de fichiers. Si ce n'est pas le cas, redirigez vers votre script PHP pour générer l'image. Lorsque vous modifiez l'image, changez le nom de fichier des images pour forcer les utilisateurs qui ont une version en cache à récupérer l'image nouvellement modifiée.

Si cela ne fonctionne pas au moins, vous n'aurez plus rien à voir avec la façon dont les images sont créées et vérifiées.

4
Goran Jurić

Une simple supposition car ce type d'analyse nécessite beaucoup de tests A/B: votre domaine .ch semble difficile à atteindre (longues bandes vertes avant l'arrivée du premier octet).

Cela signifierait que le site Web .ch est mal hébergé ou que votre FAI n'a pas une bonne route vers eux.

Compte tenu des diagrammes, cela pourrait expliquer un gros coup de performance.

Sur une note latérale, il y a cet outil cool cuzillion qui pourrait vous aider à trier les choses en fonction de votre commande de chargement de ressource.

4
Jerome WAGNER

Essayez d'exécuter les tests Y! Slow et Page Speed ​​sur votre site/page, et suivez les instructions pour éliminer les éventuels goulots d'étranglement des performances. Vous devriez obtenir d'énormes gains de performances une fois que vous obtenez un score plus élevé dans Y! Slow ou Page Speed.

Ces tests vous diront ce qui ne va pas et ce qu'il faut changer.

4
Livingston Samuel

Donc votre script PHP génère les vignettes à chaque chargement de page? Tout d'abord, si les images en miniature ne changent pas si souvent, pourriez-vous configurer un cache de sorte qu'elles n'aient pas à être analysées à chaque chargement de la page? Deuxièmement, votre script PHP utilise-t-il quelque chose comme imagecopyresampled() pour créer les vignettes? C'est un sous-échantillon non trivial et le script PHP ne renverra rien tant qu'il n'aura pas réduit les choses. L'utilisation de imagecopymerged() à la place réduira la qualité de l'image, mais accélérera le processus. Et quelle réduction faites-vous? Ces miniatures sont-elles 5% de la taille de l'image originale ou 50%? Une taille plus grande de l'image d'origine entraîne probablement un ralentissement car le script PHP doit obtenir l'image originale en mémoire avant de pouvoir la réduire et de produire une miniature plus petite.

4
MidnightLightning

Enquêter sur l'utilisation par PHP des données de session. Peut-être (juste peut-être), le script générateur d'images PHP attend de verrouiller les données de session, qui sont verrouillées par la page principale de rendu encore ou d'autres scripts de rendu d'image. rendrait toutes les optimisations JavaScript/navigateur presque hors de propos, car le navigateur attend le serveur.

PHP verrouille les données de session pour chaque script en cours d'exécution, à partir du moment où la gestion de session démarre, jusqu'au moment où le script se termine, ou lorsque session_write_close () est appelée. Cela sérialise efficacement les choses. Consultez la page PHP sur les sessions, en particulier les commentaires, comme celui-ci .

3
Ricardo Pardini

Ceci est juste une supposition sauvage car je n'ai pas regardé votre code mais je soupçonne que les sessions peuvent jouer un rôle ici, ce qui suit est de la PHP entrée manuelle sur session_write_close() :

Les données de session sont généralement stockées après la fin de votre script sans avoir besoin d'appeler session_write_close (), mais comme les données de session sont verrouillées pour empêcher les écritures simultanées, un seul script peut fonctionner sur une session à la fois. Lorsque vous utilisez des framesets avec des sessions, vous verrez les frames se charger un par un en raison de ce verrouillage. Vous pouvez réduire le temps nécessaire pour charger toutes les images en mettant fin à la session dès que toutes les modifications des variables de session sont effectuées.

Comme je l'ai dit, je ne sais pas ce que fait votre code, mais ces graphiques semblent étrangement suspects. J'ai eu un problème similaire lorsque j'ai codé une fonction de service de fichiers en plusieurs parties et j'ai eu le même problème. Lorsque je servais un gros fichier, je ne pouvais pas faire fonctionner la fonctionnalité en plusieurs parties ni ouvrir une autre page avant la fin du téléchargement. Appel de session_write_close() fixe mes deux problèmes.

3
Alix Axel

Avez-vous essayé de remplacer les thumnails générés par php par des images régulières pour voir s'il y a une différence? Le problème pourrait être autour - un bogue dans votre code php entraînant une régénération de la vignette à chaque invocation de serveur - un retard dans votre code (sleep ()?) Associé à un problème d'horloge - un problème de disque dur provoquant une très mauvaise condition de course puisque toutes les miniatures sont chargées/générées en même temps.

2
Jerome WAGNER

Je pense qu'au lieu d'utiliser ce script de générateur de vignettes, vous devez essayer TinySRC pour une génération rapide et rapide de vignettes hébergées dans le cloud. Il a une API très simple et facile à utiliser, vous pouvez utiliser comme: -

http://i.tinysrc.mobi/ [hauteur] / [largeur ] /http://domain.tld/path_to_img.jpg

[largeur] (facultatif): - Il s'agit d'une largeur en pixels (qui remplace le dimensionnement adaptatif ou familial). S'il est préfixé par "-" ou "x", il soustraira ou se réduira à un pourcentage de la taille déterminée.

[hauteur] (facultatif): - Il s'agit d'une hauteur en pixels, si la largeur est également présente. Il remplace également le dimensionnement adaptatif ou familial et peut être préfixé par "-" ou "x".

Vous pouvez consulter le résumé de l'API ici


FAQ

Combien me coûte tinySrc?

Rien.

Quand puis-je commencer à utiliser tinySrc?

Maintenant.

Quelle est la fiabilité du service?

Nous ne faisons aucune garantie sur le service tinySrc. Cependant, il fonctionne sur une infrastructure cloud distribuée majeure , il offre donc une haute disponibilité dans le monde entier. Il devrait suffire à tous vos besoins.

À quelle vitesse est-ce?

tinySrc met en cache les images redimensionnées en mémoire et dans notre magasin de données pendant 24 heures maximum , et il ne récupérera pas votre image d'origine à chaque fois. Cela rend les services incroyablement rapides du point de vue de l'utilisateur. (Et réduit la charge de votre serveur comme un effet secondaire agréable.)


Bonne chance. Juste une suggestion, puisque vous ne nous montrez pas le code: p

2
Salman von Abbas

Comme certains navigateurs ne téléchargent que 2 téléchargements parallèles par domaine, ne pourriez-vous pas ajouter des domaines supplémentaires à partager les demandes sur deux à trois noms d'hôtes différents. par exemple. 1.imagecdn.com 2.imagecdn.com

2
Tom

La majorité du problème lent est que votre TTFB (Time to first byte) est trop élevé. C'est difficile à résoudre sans devenir intime avec les fichiers de configuration de votre serveur, le code et le matériel sous-jacent, mais je peux voir qu'il sévit à chaque demande. Vous avez trop de barres vertes (mauvaises) et très peu de barres bleues (bonnes). Vous voudrez peut-être arrêter d'optimiser le frontend un peu, car je pense que vous avez fait beaucoup dans ce domaine. Malgré l'adage selon lequel " 80% -90% du temps de réponse de l'utilisateur final est passé sur le frontend ", je pense que le vôtre se produit dans le backend.

TTFB est un élément principal, un élément serveur, un prétraitement avant la sortie et une négociation.

Minutez l'exécution de votre code pour trouver des choses lentes comme des requêtes de base de données lentes, du temps pour entrer et sortir des fonctions/méthodes pour trouver des fonctions lentes. Si vous utilisez php, essayez Firephp . Parfois, il s'agit d'une ou deux requêtes lentes exécutées lors du démarrage ou de l'initialisation, comme l'extraction des informations de session ou la vérification de l'authentification, etc. L'optimisation des requêtes peut entraîner de bons gains de performances. Parfois, le code est exécuté à l'aide de php prepend ou spl autoload afin qu'ils s'exécutent sur tout. D'autres fois, il peut être mal configuré Apache conf et peaufinage qui sauve la journée.

Recherchez les boucles inefficaces. Recherchez les appels de récupération lents des caches ou les opérations d'E/S lentes causées par des lecteurs de disque défectueux ou une utilisation importante de l'espace disque. Recherchez les utilisations de la mémoire et ce qui est utilisé et où. Exécutez un test WebPagetest répété de 10 exécutions sur une seule image ou un seul fichier en utilisant uniquement la première vue à partir de différents emplacements dans le monde et non au même emplacement. Et lisez vos journaux d'accès et d'erreurs, trop de développeurs les ignorent et s'appuient uniquement sur les erreurs affichées à l'écran. Si votre hébergeur a du support, demandez-lui de l'aide, s'il ne lui demande peut-être pas poliment de toute façon, cela ne fera pas de mal.

Vous pouvez essayer DNS Prefetching pour combattre les nombreux domaines et ressources, http://html5boilerplate.com/docs/DNS-Prefetching/

Le serveur est-il le vôtre? Parfois, un meilleur serveur peut résoudre de nombreux problèmes. Je suis un fan de la mentalité ' le matériel est bon marché, les programmeurs sont chers ', si vous avez la chance et l'argent de mettre à niveau un serveur. Et/ou utilisez un CDN comme maxcdn ou cloudflare ou similaire.

Bonne chance!

(p.s. je ne travaille pour aucune de ces sociétés. De plus, le lien cloudflare ci-dessus fera valoir que le TTFB n'est pas si important, je l'ai ajouté pour que vous puissiez obtenir une autre prise.)

1
Anthony Hatzopoulos

Avez-vous essayé de configurer plusieurs sous-domaines sous serveur Web NGINX spécialement pour servir des données statiques comme des images et des feuilles de style? Quelque chose d'utile a déjà été trouvé dans cette rubrique .

1
nefo_x

En ce qui concerne les vignettes retardées, essayez d'appeler flush () immédiatement après le dernier appel à header () dans votre script de génération de vignettes. Une fois cela fait, régénérez votre graphique en cascade et voyez si le retard est maintenant sur le corps au lieu des en-têtes. Si c'est le cas, vous devez jeter un long regard sur la logique qui génère et/ou sort les données d'image.

Le script qui gère les miniatures devrait, espérons-le, utiliser une sorte de mise en cache afin que les actions qu'il entreprend sur les images que vous servez ne se produisent qu'en cas de nécessité absolue. Il semble qu'une opération coûteuse ait lieu chaque fois que vous servez les miniatures, ce qui retarde toute sortie (y compris les en-têtes) du script.

1
A. R. Younce

Tout d'abord, vous devez gérer If-Modified-Since demandes et telles à juste titre, comme l'a dit James. Cette erreur indique que: "Lorsque je demande à votre serveur si cette image est modifiée depuis la dernière fois, il envoie l'image entière au lieu d'un simple oui/non".

Le temps entre la connexion et le premier octet est généralement le temps nécessaire à l'exécution de votre script PHP. Il est évident que quelque chose se produit lorsque ce script commence à s'exécuter.

  1. Avez-vous envisagé de le profiler? Il peut y avoir quelques problèmes.
  2. Combiné avec le problème ci-dessus, votre script peut s'exécuter beaucoup plus de fois que nécessaire. Idéalement, il devrait générer des vignettes uniquement si l'image d'origine est modifiée et envoyer des vignettes mises en cache pour chaque autre demande. Avez-vous vérifié que le script génère les images inutilement (par exemple pour chaque demande)?

La génération d'en-têtes appropriés via l'application est un peu délicate, de plus ils peuvent être écrasés par le serveur. Et vous êtes exposé à des abus car quiconque envoie des en-têtes de demande sans cache provoquera l'exécution continue de votre générateur de vignettes (et augmentera les charges). Donc, si possible, essayez d'enregistrer ces vignettes générées, appelez les images enregistrées directement à partir de vos pages et gérez les en-têtes à partir de .htaccess. Dans ce cas, vous n'aurez même pas besoin de quoi que ce soit dans votre .htaccess si votre serveur est correctement configuré.

En dehors de ceux-ci, vous pouvez appliquer certaines des idées d'optimisation brillantes des parties performances de cette Nice globale SO question sur comment faire les sites Web de la bonne façon , comme le fractionnement vos ressources dans des sous-domaines sans cookies, etc. Mais en tout cas, une image 3k ne devrait pas prendre une seconde à charger, cela est apparent par rapport aux autres éléments dans les graphiques. Vous devriez essayer de repérer le problème avant de l'optimiser.

1
Halil Özgür