L'étrange cas de M. Time To First Byte

14

J'ai un serveur Web sur un Linode 1024 VPS basé sur

  • Ubuntu 11.10
  • Nginx 1.0.5
  • PHP 5.3.6 (avec PHP-FPM, APC)
  • Vernis 3.0.2

Et quelques blogs basés sur WordPress 3.3.1. L'un d'eux est un simple blog, avec la configuration par défaut, le thème et juste le message "Hello World", pour tester le serveur. L'autre est un blog cloné à partir d'un autre serveur avec près de 10 000 articles et plus de 10 000 commentaires. Ce blog compte environ 5k uniques par jour.

Le serveur donne de bons chiffres sur un test ab pour le blog de test , mais le même test avec le blog cloné est impossible à faire: le test ab charge trop le serveur, et je dois arrêter le processus, ce qui fait de toute façon ab pour montrer ce résultat vraiment médiocre .

Le htop montre également une charge "normale" en fonctionnement normal , mais une grosse charge anormale pendant le test ab.

Il se passe une autre chose étrange (la plus importante pour moi): le Time To First Byte est extrêmement élevé , mais après cela, le site se charge très rapidement. Cela peut être facilement testé avec des services tels que tools.pingdom.com, qui donne ce résultat . Veuillez faire attention à cette région jaune qui signifie "Temps d'attente".

Pourquoi cela arrive-t-il? Idées possibles:

  • Mauvaise configuration PHP-FPM
  • Le temps de réponse DNS de Linode est horrible. Non-sens - le blog de test résout bien DNS, TTFB est fantastique
  • Configuration de Bad Nginx

Si quelqu'un a besoin de plus d'informations,

javipas
la source
Je pense que cela peut avoir quelque chose à voir avec la if -fdirective que vous utilisez dans le locationconteneur dans la configuration nginx. Sur la base de ce que je lis ici wiki.nginx.org/Pitfalls , j'ai le sentiment que le -ffait une recherche inefficace du fichier qui pourrait provoquer un problème de Time To First Byte, surtout si vous avez des répertoires avec un grand nombre de des dossiers.
d34dh0r53
1
Quelques réflexions: a) quelles sont les différences par rapport au serveur d'origine à partir duquel le blog est cloné (par exemple, exécute-t-il la même pile?) B) si vous le pouvez, exécutez ab directement depuis le serveur en utilisant localhost et le port. Essayez d'accéder via le vernis, puis accédez directement à nginx). c) Activer les journaux lents MySQL et PHP-FPM. d) lancez mysqltuner.pl et voyez si vous pouvez améliorer vos performances MySQL (ce serait la différence la plus évidente entre les blogs - ou plugins). e) La configuration PHP-FPM que vous avez publiée ne semble pas être celle utilisée par nginx (/var/run/php5-fpm-tpnet.sock! = /var/run/php5-fpm-www-data.sock)
cyberx86
1
Certainement un problème PHP. Wordpress est vraiment lent. Vous aurez besoin d'un plugin de mise en cache pour obtenir un temps de chargement décent lorsque vous avez autant de contenu.
Martin Fjordvald
2
Vous avez dit que vous pouvez exécuter ab sur localhost et obtenir 4 000 demandes / s - de quel localhost (précédent / actuel) parlez-vous? Si cette valeur provient de votre serveur actuel - celui avec le TTFB élevé - alors votre problème est devenu beaucoup plus intéressant - puisque vous avez effectivement éliminé PHP, MySQL et votre serveur Web. TTFB comprend le DNS, le temps d'aller-retour et le temps de traitement. Un TTFB long est généralement dû au traitement (par exemple PHP / MySQL). Le point de lancer ab directement contre nginx est d'éliminer les autres composants. En outre, Varnish, s'il est correctement configuré, devrait contourner le backend, ce qui donne une demande / s très élevée.
cyberx86
1
Vos tests d'hôte local ne semblent pas valides - vous n'avez pas réellement récupéré votre blog. Notez la différence de taille de page: 7500 octets lorsque vous y accédez depuis le domaine, 151 octets depuis localhost. Comme vous avez probablement plusieurs hôtes virtuels, vous devez passer l'en-tête de l'hôte à ab. ab -n 1000 -c 100 -H 'Host: mysite.com' http://127.0.0.1/Cela dit, la différence entre les résultats mis en cache (vernis) et non mis en cache est suffisante pour valider la position selon laquelle le problème n'est pas lié au réseau, au DNS, etc. et réside dans le traitement, comme prévu.
cyberx86

Réponses:

24

Tout d'abord, ce n'est pas une réponse, mais une approche diagnostique.

Ce n'est en aucun cas complet - ou même quelque chose de proche, ce n'est qu'un point de départ.

Temps jusqu'au premier octet

Le délai jusqu'au premier octet (TTFB) comprend un certain nombre de composants:

  • Recherche DNS: Trouver l'adresse IP du domaine (amélioration possible: serveurs DNS plus nombreux / distribués / réactifs)
  • Temps de connexion: ouvrez un socket sur le serveur, négociez la connexion (la valeur typique devrait être autour du temps de «ping» - un aller-retour est généralement nécessaire - keepalive devrait aider pour les demandes ultérieures)
  • En attente: le traitement initial requis avant l'envoi du premier octet (c'est là que devrait être votre amélioration - ce sera le plus important pour le contenu dynamique.

Lorsque vous regardez une sortie ApacheBench, vous voyez également:

  • Traitement: il s'agit de la somme de l'attente + du transfert complet du contenu (si le temps de transfert est nettement plus long que ce qui serait attendu pour télécharger la quantité de données reçues, un traitement supplémentaire (après le premier octet reçu) est en cours (par exemple, la page est vidage du contenu tel qu'il est disponible)

Comparaisons pour éliminer les composants

À quelques exceptions près, votre problème va résider dans le traitement backend, qui se résume généralement à un code trop complexe / inefficace ou à une configuration MySQL mal configurée.

Un bon moyen d'aborder ce problème consiste à effectuer une série de comparaisons qui élimineront divers aspects de votre configuration. Une bonne comparaison doit rester aussi constante que possible pour aider à réduire le problème. Actuellement, vous avez fourni les comparaisons suivantes:

  1. Site identique (cloné) fonctionnant sur l'ancien serveur et le nouveau serveur:
    • Différence: serveur
    • Résultat: l'ancien serveur est rapide; le nouveau serveur est lent
    • Notes: Ce dont vous avez besoin ici est de quantifier les différences entre ces serveurs - à la fois en termes de pile utilisée (Nginx, etc.) et de matériel (l'ancien serveur est-il plus rapide car c'est une machine plus puissante?)
    • Conclusion: le code peut fonctionner rapidement sur la bonne configuration
  2. Site de test vs site complet sur le nouveau serveur
    • Différence: contenu, thèmes, plugins, etc.
    • Résultat: le site de test est rapide, le site complet est lent
    • Remarques: en théorie, ce test devrait vous aider à éliminer de nombreux aspects de votre configuration - DNS, réseau, même votre configuration nginx / php / mysql - cependant, ce n'est pas tout à fait «juste».
    • Conclusion: le contenu supplémentaire a un impact significatif sur les performances

Le test idéal vous obligerait à dupliquer votre site complet, puis à supprimer tout le contenu, sauf un article et les commentaires associés. Le but de ce test serait de déterminer de manière concluante si la grande quantité de contenu est le problème ou si d'autres aspects de votre configuration (plugins wordpress, thème, etc.) en sont la cause. Vous compareriez essentiellement les performances de sites identiques, sur le même (nouveau) serveur - en chargeant la même page (même longueur, etc.) - avec la seule différence étant le contenu total du site (par exemple, il y a de fortes chances qu'un plugin ne le fasse pas). bien évoluer avec un contenu accru).

Sans rien changer, vous pouvez faire d'autres comparaisons:

  • Test à partir d'un emplacement distant par rapport à local - cela aidera à identifier si le réseau, la latence, le DNS, etc. sont la cause
    • Vous avez déjà (quelque peu) fait cela et avez principalement conclu que vous n'aviez pas de problème de réseau.
  • Testez via Varnish (c'est-à-dire le port 80) vs nginx directement (port 8080) - essayez de ne pas changer votre configuration entre les tests - utilisez simplement le bon port. Cela vous montrera l'impact du vernis. Étant donné que Varnish est une couche de mise en cache, il devrait servir très rapidement toutes les demandes après la première - essentiellement, il devrait contourner le backend et le traitement nécessaire pour générer une page dynamique et servir la copie en cache très rapidement.
    • Vous l'avez fait (mais pas localement) et vous avez démontré que Varnish a un impact positif significatif sur vos performances.

Réglage de votre backend

À ce stade, vous devriez soit avoir trouvé le problème, soit conclu qu'il se trouve dans votre backend. Cela vous laisse Nginx, PHP ou MySQL.

(Je dois mentionner ici, qui est - il toujours utile de savoir si votre goulot d' étranglement est CPU, RAM, ou E / S - entre sar, top, iostat, vmstat, free., Etc , vous devriez être en mesure de venir à une conclusion à ce sujet )

Nginx

Nginx prend simplement les demandes et sert du contenu statique ou déplace les demandes vers PHP-FPM - il n'y a généralement pas grand-chose à optimiser avec Nginx.

  • Définir les travailleurs = # cœurs de processeur
  • Activer keepalive (une valeur de 10-15 est bonne)
  • Désactiver la journalisation inutile
  • Augmentez la taille des tampons si nécessaire
  • Évitez les instructions if (utilisez des noms statiques au lieu d'expressions rationnelles dans la mesure du possible, éliminez les extensions inutiles)

Idéalement, votre blog de test et votre blog cloné ont des configurations identiques, auquel cas, vous avez effectivement éliminé Nginx comme problème.

Application

Dans le cas où vous essayez d'identifier un problème dans votre code (par exemple un plugin lent, etc.), les journaux lents sont le point de départ.

  • Activez le journal lent MySQL et le journal lent PHP-FPM exécutez votre benchmark et voyez ce qui se présente comme lent.

MySQL

  • Augmentez vos caches et exécutez mysqltuner.pl pour obtenir un bon point de départ.

PHP

  • désactiver les extensions inutiles,
  • désactiver register_globals, magic_quotes_ *, expose_php, register_argc_argv, always_populate_raw_post_data
  • augmenter la mémoire_limit
  • open_basedir et safe_mode ont d'importantes implications en termes de performances, mais peuvent également fournir une couche de défense supplémentaire. Testez avec et sans eux, pour déterminer si leur impact sur les performances est tolérable.

PHP-FPM

  • Ajustez les valeurs pm. * - augmentez-les pour faire face à une charge élevée

Il convient de noter que vos résultats htop montrent que php-fpm consomme la majeure partie du processeur - et votre problème semble être directement lié à cela.

Mise en cache

Une fois que vous avez optimisé chaque goulot d'étranglement probable, commencez la mise en cache.

  • Vous disposez déjà d'un cache opCode (APC) - assurez-vous qu'il fonctionne (il est fourni avec un fichier de test) - vérifiez vos taux d'accès au cache et, si possible, mettez le cache APC en mémoire plutôt qu'au disque.
  • Configurez votre code pour le mettre en cache (par exemple en utilisant un plugin pour Wordpress tel que W3TC)
  • Avec nginx, vous pouvez configurer la mise en cache FastCGI - mais comme vous avez Varnish, il vaut mieux éviter cela.
  • Configurez une couche de mise en cache, telle que Varnish (ce que vous avez déjà fait) - et assurez-vous qu'elle fonctionne (par exemple, utilisez varnishstat, lisez Atteindre un taux de réussite élevé )
  • Ajoutez plus de cache pour les composants de votre site - par exemple MemCached si applicable

Parfois, étant donné les limites de votre application et de votre matériel, il se peut que vous ne puissiez pas améliorer les performances du backend autant - cependant, c'est le point de la mise en cache - pour minimiser l'utilisation du backend.

Lectures complémentaires

cyberx86
la source
2
Voilà un résumé fantastique des points à analyser. Merci beaucoup pour le commentaire, je vais essayer d'effectuer un test lourd avec toutes ces suggestions -certaines d'entre elles, comme vous l'avez dit, sont déjà claires- et voir si je peux enfin détecter le problème. Cordialement, cyberx86.
javipas
À propos de la memory_limit, il a été souligné dans un autre post que cela n'aide pas les performances.
forloop