Laravel & PHP
Diagnostiquer une application Laravel lente : par où commencer
Quand une application Laravel ralentit, le premier réflexe — réécrire le code — est presque toujours le moins efficace. Voici l’ordre de diagnostic qui évite de refactoriser un problème d’infrastructure.
Réponse directe
Une application Laravel lente vient le plus souvent, par ordre de fréquence, de requêtes SQL mal maîtrisées, de relations Eloquent chargées en N+1, d’un cache absent ou mal invalidé, d’appels vers des services externes lents, d’une saturation de PHP-FPM, ou enfin d’une infrastructure sous-dimensionnée. Le framework en lui-même est rarement la cause racine : le bon réflexe consiste à mesurer avant de refactoriser.
Le piège le plus courant consiste à conclure « Laravel est lent » à partir d’un temps de réponse élevé. Ce temps de réponse est un symptôme mesuré, pas un diagnostic. Il peut venir de six couches différentes, et le traiter au mauvais endroit coûte cher sans rien résoudre.
Étape 1 : mesurer avant de conclure
Sans mesure reproductible, la discussion reste une discussion d’impressions. Trois sources de données se complètent et ne coûtent presque rien à installer.
- Les logs d’accès du serveur : temps de réponse réel, distribués par URL. Ils montrent la vérité perçue par les utilisateurs, y compris sur les pages que l’on croyait rapides.
- Les métriques applicatives : nombre de requêtes SQL par page, durée cumulée, requêtes dupliquées. Elles expliquent le temps passé côté base de données.
- Les métriques système : charge CPU, mémoire, entrées-sorties, connexions actives. Elles expliquent ce que l’infrastructure ne peut plus absorber.
# Les pages les plus lentes réellement servies (format Nginx combined)
awk '{print $9, $7}' /var/log/nginx/access.log | sort -k1 -n -r | head -20
# Fréquence d'utilisation de chaque page
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20Étape 2 : compter les requêtes SQL par page
C’est le premier chiffre à obtenir, et le plus souvent le plus parlant. Une page qui exécute cinquante requêtes pour afficher une liste en contient probablement la moitié de trop.
// Journaliser chaque requête SQL, sans dépendance externe
DB::listen(function ($query) {
Log::info('sql', [
'sql' => $query->sql,
'time' => $query->time, // en millisecondes
]);
});Ce journal se lit ensuite comme un inventaire : quelles requêtes reviennent sur chaque page, lesquelles dépassent les 100 ms, lesquelles sont identiques d’une requête à l’autre et pourraient donc être mises en cache.
Étape 3 : traquer les requêtes N+1
Une requête N+1 se produit lorsqu’on charge une collection, puis qu’on accède à une relation pour chaque élément. En développement, sur trois lignes, cela passe inaperçu. En production, sur plusieurs milliers, cela devient le principal facteur de lenteur d’une page.
// Problème : une requête par élément de la collection
foreach ($orders as $order) {
$total += $order->lines->sum('amount');
}
// Correctif : les relations sont chargées en une seule requête
$orders = Order::with('lines')->get();
// Alternative : laisser la base agréger
$total = OrderLine::whereIn('order_id', $ids)->sum('amount');Deux outils complètent cette lecture : le compteur de requêtes intégré à Laravel signale les pages qui en génèrent trop, et un profileur comme Telescope ou Debugbar facilite l’inspection visuelle du nombre de requêtes par route.
Étape 4 : vérifier le cache et son invalidation
Un cache absent se traduit par un recalcul permanent. Un cache mal invalidé se traduit par un problème plus ingrédient : des données obsolètes que l’équipe ne comprend plus et finit par contourner.
- Vérifier que le cache de configuration, de routes et de vues est actif en production. Mal configurer cette étape est une cause fréquente de ralentissement brutal.
- Identifier les données réellement identiques d’une requête à l’autre : référentiels, paramètres, listes déroulantes.
- Définir explicitement les règles d’invalidation. Une donnée en cache sans règle claire devient une source d’erreurs métier.
Étape 5 : mesurer les appels externes
Un appel vers une API tierce est une dépendance dont on ne contrôle ni la latence ni l’indisponibilité. C’est souvent la cause des ralentissements « par vagues », sans lien avec la charge du site.
HTTP::timeout(3)->retry(2, 200)->get($endpoint);
// Mesurer chaque appel pour distinguer notre latence de la leur
$start = microtime(true);
$response = Http::timeout(3)->get($endpoint);
Log::info('external-call', [
'endpoint' => $endpoint,
'duration' => round((microtime(true) - $start) * 1000), // ms
'status' => $response->status(),
]);Étape 6 : vérifier PHP-FPM et l’infrastructure
Si les étapes précédentes sont écartées, la lenteur vient probablement de la couche d’exécution ou de l’hébergement. Les indices sont alors dans les journaux du serveur, pas dans le code.
# Processus enfants : la saturation se voit au nombre et à la consommation
ps -o pid,ppid,pcpu,pmem,rss,etime -C php-fpm 2>/dev/null | head -20
# Connexions et file d'attente réseau
ss -s
# Charge, mémoire et entrées-sorties
uptime
free -m
iostat -x 1 3 2>/dev/null || vmstat 1 3Une saturation de PHP-FPM se reconnaît à un grand nombre de processus enfants actifs en permanence, souvent avec une consommation mémoire élevée. Dans ce cas, l’application a plus de travail à faire que l’infrastructure ne peut en exécuter, et le levier est le dimensionnement ou l’allègement des requêtes, pas le framework.
Synthèse : l’ordre de diagnostic
| Étape | Source | Symptôme |
|---|---|---|
| 1. Mesurer | Logs d’accès, métriques | Temps de réponse élevé, sur quelles pages ? |
| 2. Requêtes SQL | Journal applicatif, requêtes lentes | Pages lentes et nombre de requêtes élevé |
| 3. Eloquent | Relations dans les boucles | Requêtes dupliquées, N+1 |
| 4. Cache | Configuration, invalidations | Recalcul permanent ou données obsolètes |
| 5. Appels externes | Latence mesurée | Ralentissements par vagues |
| 6. PHP-FPM | Processus, mémoire | File d’attente, CPU saturée |
| 7. Infrastructure | Charge, entrées-sorties, réseau | Ralentissement généralisé |
Cet ordre n’est pas arbitraire : il va du plus probable et du moins coûteux à corriger au plus général. On ne refactorise une application qu’après avoir écarté la base de données, le cache et la couche d’exécution. Pour la suite du diagnostic, le diagnostic d’un serveur Linux détaille les étapes suivantes.
Quand faire appel à un spécialiste
Un diagnostic externalisé devient pertinent quand le ralentissement persiste malgré des optimisations évidentes, quand plusieurs couches sont suspectes simultanément, ou quand l’équipe interne n’a pas les outils pour mesurer. L’intérêt d’un audit n’est pas de recevoir une liste d’optimisations, mais de savoir quelle cause a été confirmée et, par conséquent, quel chantier a réellement du sens.
À lire également
Des contenus du même cluster, sélectionnés selon la proximité du sujet et non au hasard.
Reprise & maintenance
Auditer une application Laravel existante avant de la reprendre
Reprendre une application Laravel ne commence pas par le code. Les versions, les dépendances, les requêtes et l’état de la production décident de la stratégie.
LireInfrastructure & DevOps
Comment auditer un serveur Linux en production
Un audit serveur commence toujours par la sécurité et la capacité de restauration, jamais par la mise à jour du système. Voici l’ordre de travail que j’applique sur une production en service.
LireUne application Laravel lente en production ?
Le diagnostic mesure d’abord où passe le temps — requêtes, cache, PHP-FPM, infrastructure — avant de décider si le code doit être modifié.