Serveur ou application : comment mesurer le goulot d'étranglement
Le temps jusqu'au premier octet à chaque saut, les compteurs de marge de la machine et le slow log groupé par frame bloquante situent un site lent dans une couche avant tout changement.
Dans cet article 7 sections
- Mesurez le temps jusqu'au premier octet à chaque saut : à travers le edge, directement vers l'origine, et sur localhost. Le plus grand écart entre deux nombres adjacents est la couche qui possède la latence.
- Lisez la marge de la machine pendant qu'elle est lente : CPU idle et steal, mémoire disponible, await disque et profondeur de file. De la marge partout sous un site lent signifie que la contrainte se situe au-dessus du matériel.
- À l'intérieur de la couche applicative, agrégez : requêtes par URL, requêtes lentes par frame bloquante, requêtes SQL par digest. Chacune réduit des milliers de lignes à une courte liste classée avec un ou deux noms en tête.
Le temps jusqu'au premier octet à chaque saut
Les théories sur un site lent se forment facilement et se tranchent difficilement. Trois mesures les tranchent. Prenez le temps jusqu'au premier octet à travers le edge public, de nouveau directement vers l'origine en contournant le edge, et de nouveau sur l'hôte de l'application vers localhost. La différence entre deux relevés adjacents est le coût de cette couche.
# through the edge
curl -s -o /dev/null -w 'dns=%{time_namelookup} tls=%{time_appconnect} ttfb=%{time_starttransfer}\n' https://site.example/
# direct to the origin, edge bypassed
curl -s -o /dev/null -w 'ttfb=%{time_starttransfer}\n' --resolve site.example:443:ORIGIN_IP https://site.example/
# on the host, nothing in front of the application
curl -s -o /dev/null -w 'ttfb=%{time_starttransfer}\n' http://127.0.0.1/Ce qui reste sur localhost est l'application et les services qu'elle appelle. La couche avec le plus grand écart est là où va le reste du travail.
La marge pendant que ça fait mal
Lisez les compteurs pendant la période lente, pas après.
vmstat 1 5 # r (run queue), wa (I/O wait), st (steal), id (idle)
iostat -x 1 5 # await and aqu-sz per device
free -m # the available column, not usedUne longue run queue avec peu d'idle est une machine limitée par le CPU. Un I/O wait élevé avec un await élevé sur le périphérique, c'est le stockage. Le steal est un voisin sur un hyperviseur partagé qui prend des cycles que le guest voulait. Un CPU inactif, de la mémoire disponible et des périphériques à faible await sous un site lent signifient que la machine attend quelque chose qui ne lui appartient pas : un appel externe, un verrou, une requête lente pour des raisons autres que le matériel. Ajouter du matériel à ce stade produit une machine plus inactive qui est toujours lente.
Il existe une troisième catégorie entre les deux, et elle est courante : le pool. La page de statut de PHP-FPM montre une listen queue. Une file de requêtes en attente avec un CPU inactif signifie que chaque worker est occupé, généralement bloqué sur le même appel lent, et que le site est lent à cause d'un plafond de configuration plutôt que d'un plafond de ressources. La même forme apparaît comme un pool de connexions de base de données saturé ou une file de backend HAProxy pleine. La machine est innocente et le code n'est pas encore condamné. La taille du pool et l'appel qu'il attend sont les deux relevés suivants.
Lisez le trafic avant le code
Le log d'accès dit de quel type de problème il s'agit. Trouvez d'abord le log par vhost. Le log par défaut peut ne contenir qu'une petite fraction du trafic réel, et un comptage sur le mauvais fichier donne une réponse fausse avec assurance.
tail -n 100000 access.log | awk -F'"' '{print $2}' | sort | uniq -c | sort -rn | headQuelques URL répétées des milliers de fois, c'est le site qui s'appelle lui-même, et la solution est un cache devant ces URL. Des requêtes qui avancent dans l'ordre du sitemap, c'est un crawler, et la solution est un rate limit. Une hausse large et uniforme sur de nombreuses URL, c'est de la demande, et la solution est de la capacité.
Condensez le slow log et le log de requêtes
Un slow log est un tas de stack traces tant qu'il n'est pas groupé. Activez le slow log de PHP-FPM avec un seuil qui attrape les requêtes dont les utilisateurs se plaignent, puis groupez chaque trace sur la frame dans laquelle elle était bloquée, la feuille, et comptez. La liste classée est courte et sa tête est généralement un appel externe ou une requête SQL.
Côté base de données, classez par digest, pas par plan. Une paramétrisation incohérente éclate une requête logique en de nombreux plans qui paraissent chacun inoffensifs. Sommé par digest, le vrai propriétaire du temps de la base se rassemble en une seule ligne.
-- MySQL and Percona: by statement digest
SELECT digest_text, count_star, sum_timer_wait
FROM performance_schema.events_statements_summary_by_digest
ORDER BY sum_timer_wait DESC
LIMIT 10;
-- SQL Server: by query hash
SELECT query_hash, COUNT(*) AS plans, SUM(total_worker_time) AS cpu
FROM sys.dm_exec_query_stats
GROUP BY query_hash
ORDER BY cpu DESC;Avant d'écrire un index, vérifiez le nombre réel de lignes et les index qui existent déjà. Un index sur une table qui n'en a pas besoin est un chemin d'écriture plus lent.
Lisez la source primaire, pas une histoire plausible
| L'histoire | La source qui la tranche |
|---|---|
| Ça a planté, il n'y avait plus de mémoire | dmesg, journalctl --list-boots, last -x reboot : a-t-elle redémarré, et pourquoi |
| La base de données est corrompue | le propre log d'erreurs de la base, grepé pour les messages de crash et de corruption |
| Un processus emballé mange le CPU | ps --forest et /proc/<pid>/cmdline : sa vraie identité et son parent, pas un nom plausible |
| Nous voyons des erreurs d'intégrité | ethtool -S sur l'interface : zéro erreur sur le câble signifie que le problème est au-dessus du câble |
| SELinux le bloque | ausearch -m avc -ts recent envoyé dans audit2why : le refus, nommé, avec le module de politique qui le corrige |
Chaque ligne remplace une théorie par un relevé. La dernière compte sur un système en mode enforcing : le journal d'audit répond à la question sans changer la posture de sécurité pour la poser.
Prouvez-le, puis vérifiez avec la même mesure
La corrélation donne un suspect. Une petite perturbation réversible le condamne : arrêtez les requêtes suspectes quelques secondes et regardez si la charge se reconstitue. Si elle se reconstitue aussitôt, le trafic en direct est le moteur et la solution appartient au edge, devant les requêtes qui ne devraient même pas atteindre la base. Tant que la cause n'est pas connue, le système est en lecture seule. Quand la correction est en place, elle est vérifiée avec la mesure qui a trouvé le problème : si le temps jusqu'au premier octet par saut l'a localisé, le temps jusqu'au premier octet par saut confirme qu'il a disparu.
Ce que nous corrigeons et ce que nous vous rendons
| Au edge, le jour même | Dans votre code, avec le changement exact |
|---|---|
| Micro-caching avec request collapsing devant les URL chaudes | Déplacer l'appel tiers synchrone dans un job en arrière-plan avec un timeout et un fallback |
| Pools de workers et de buffers dimensionnés sur la charge mesurée | Retirer la boucle de rendu ou la boucle de retry |
| Un covering index ajouté en ligne | Faire expirer les données applicatives qui grossissent sans limite |
| Retries et timeouts HAProxy ajustés, un contexte SELinux corrigé | Alléger le payload et les scripts envoyés au navigateur |
Nous ne changeons pas votre code. Nous nommons la ligne, montrons la mesure qui la désigne et gardons le site en ligne pendant que vous la corrigez.
Réponses directes
Comment savoir si c'est mon serveur ou mon application qui est lent ?+
Lisez la marge pendant la période lente : CPU idle et steal, mémoire disponible, await disque. Si les trois ont de la place, la contrainte est au-dessus du matériel, dans l'application ou dans un service qu'elle appelle. Le temps jusqu'au premier octet sur localhost comparé au edge confirme quelle couche.
Comment trouvez-vous une requête de base de données lente ?+
Nous classons par digest, pas par plan handle, pour qu'une requête logique avec de nombreuses paramétrisations montre son coût total sur une seule ligne. Puis nous vérifions les nombres de lignes et les index existants avant d'écrire le moindre DDL.
Pouvez-vous distinguer un bot d'un vrai pic de trafic ?+
D'après le log d'accès, par fréquence des URL. Une poignée d'URL répétées des milliers de fois, c'est le site qui s'appelle lui-même, l'ordre du sitemap est un crawler, une hausse large est de la demande. Chacun reçoit une solution différente.
Changez-vous mon code ?+
Non. Tout ce qui relève de l'infrastructure, nous le corrigeons au edge le jour même, de façon réversible. Tout ce qui est dans votre code, nous vous le rendons sous forme du changement exact, avec la mesure qui le justifie.
Votre site est lent et personne n'est d'accord sur la raison.
Parlez à un ingénieur qui mesure chaque saut avant de toucher à quoi que ce soit.
Parler à un ingénieurVous êtes arrivé à la fin.
Mettez la lecture en pratique
Que faites-vous tourner ?
Parlez-nous de la charge de travail, du trafic et des exigences de reprise. Commencez par le configurateur de serveur, ou passez en revue les détails avec un ingénieur.
Écrit par les ingénieurs qui construisent et exploitent l'infrastructure qu'il décrit.Parler à un ingénieur
