Scaler

Optimiser une API lente : les causes fréquentes

· 6 min de lecture · par l'équipe Agenticiel

Une API qui répond en deux secondes au lieu de deux cents millisecondes ne se répare pas en ajoutant de la puissance. Dans la plupart des cas, le problème n’est pas la machine, mais une série de choix techniques qui, chacun pris isolément, semble anodin, et qui finissent par se cumuler jusqu’à rendre le service inutilisable.

La difficulté de ce type d’optimisation est qu’elle ne se devine pas. Deux API lentes peuvent être lentes pour des raisons totalement différentes, et la cause n’est presque jamais là où l’on croit. Corriger au hasard, c’est perdre du temps et introduire des régressions.

Voici les causes les plus fréquentes de lenteur côté serveur, dans l’ordre où il faut les chercher, à appliquer comme une liste de contrôle.

Mesurer avant de corriger

La première erreur est de corriger avant d’avoir mesuré. Une API est un enchaînement de couches : le réseau, le framework, la logique applicative, la base de données, et parfois des services externes. La lenteur se situe presque toujours dans une seule de ces couches, et un bon outil de traçage la désigne en quelques minutes.

Les traces distribuées sont ici l’outil central, avec OpenTelemetry comme standard et Datadog, Sentry ou Grafana pour les lire. Elles permettent de suivre une requête à travers toutes les couches et de voir, pour chaque étape, le temps passé. Quand une requête met deux secondes et que la trace montre 1,8 seconde dans un appel de base de données, vous savez où chercher. Sans cette mesure, vous optimisez à l’aveugle.

Les profils de performance de type APM apportent la même information sur la durée, en identifiant les points chauds qui reviennent sur toutes les requêtes. Commencez par brancher l’un ou l’autre, mesurez sur un trafic réel ou rejoué, puis corrigez ce que la mesure désigne.

Le problème N+1, la cause la plus fréquente

Le problème N+1 est sans doute la cause de lenteur la plus répandue dans les applications qui utilisent un ORM. Il se produit quand une requête principale récupère une liste d’objets, puis que le code exécute une requête supplémentaire pour chaque élément de la liste afin de charger une donnée associée.

Le symptôme est caractéristique : une page qui affiche cinquante éléments déclenche cinquante et une requêtes au lieu d’une ou deux. Chacune est rapide, mais leur accumulation transforme une réponse instantanée en une réponse qui traîne. La cause est souvent une relation chargée en mode paresseux, déclenchée à l’intérieur d’une boucle.

Le correctif consiste à charger les données associées en une seule requête, par jointure ou par chargement anticipé (un include avec Prisma, une sélection imbriquée avec le client Supabase). C’est un changement de quelques lignes qui peut diviser le temps de réponse par dix ou par cent. La leçon plus large est qu’il faut inspecter les requêtes réellement émises, pas seulement le code : le N+1 se cache précisément là où le code paraît propre. On le retrouve très souvent dans les produits générés rapidement avec Lovable, Bolt, v0, Cursor ou Claude Code, où l’ORM est utilisé tel que l’assistant l’a proposé, sans regard sur les requêtes produites.

Les requêtes sans index et les jointures coûteuses

Quand la base de données est le goulot, la cause est le plus souvent une absence d’index. Une requête qui balaye une table entière répond vite tant que la table est petite, puis se dégrade à mesure que les données s’accumulent. La requête a toujours été coûteuse ; la petite taille des données le masquait.

L’index manquant se repère en examinant les requêtes lentes et leur plan d’exécution (pg_stat_statements et EXPLAIN ANALYZE sous PostgreSQL). Une requête qui parcourt des millions de lignes pour en renvoyer trois est une requête qui attend un index. Le correctif est immédiat et sans risque : poser l’index, puis vérifier que le plan d’exécution l’utilise réellement.

Les jointures trop larges relèvent du même diagnostic, avec une nuance : elles peuvent être coûteuses même avec les bons index, parce qu’elles brassent trop de données. La correction consiste alors à réduire ce que la requête ramène, en ne sélectionnant que les colonnes nécessaires et en paginant. La règle est simple : ne jamais demander à la base plus de données que ce que la réponse de l’API va réellement exposer. Quand les index et les requêtes ne suffisent plus, c’est la base elle-même qu’il faut faire évoluer : voyez notre plan d’action pour scaler une base de données.

La sérialisation et la taille des réponses

Une cause de lenteur souvent négligée est la sérialisation : transformer les objets en JSON avant de les renvoyer. Quand la réponse contient des objets imbriqués, avec des champs inutiles ou des données redondantes, la sérialisation peut prendre plus de temps que la requête elle-même.

Le problème n’est pas seulement le temps de calcul, mais la taille de la charge utile. Une réponse de plusieurs mégaoctets est lente à produire, lente à transférer, et lente à traiter du côté du client. Beaucoup d’API renvoient l’intégralité des objets de leur modèle alors que le client n’en exploite qu’une petite partie.

Le correctif est de renvoyer exactement ce dont le client a besoin, ni plus ni moins. On sélectionne les champs, on évite de sérialiser des relations entières quand un identifiant suffit, et on compresse les réponses volumineuses.

Les appels synchrones qui devraient être asynchrones

Une API lente contient souvent des opérations qui n’ont pas leur place dans le chemin de la requête : l’envoi d’un email de confirmation, la génération d’une facture PDF, la mise à jour d’un index de recherche, ou un appel à un LLM (GPT, Claude, Mistral) qui prend plusieurs secondes. Ces traitements rendent la réponse plus lente alors que l’utilisateur n’a pas besoin de leur résultat pour continuer.

Le correctif est de sortir ces opérations du chemin synchrone, en les mettant dans une file d’attente traitée en arrière-plan (BullMQ sous Node.js, Celery sous Python, ou un service comme Amazon SQS). Pour une réponse de LLM que l’utilisateur attend, le streaming affiche le texte au fil de l’eau. La réponse revient immédiatement, et le traitement long se fait à son rythme. C’est une transformation d’architecture plus lourde que les précédentes, mais c’est souvent celle qui produit le gain le plus durable, et un premier pas vers une API capable de monter en charge (par où commencer pour scaler une API).

Le point délicat est de gérer les cas où l’utilisateur attend réellement le résultat : on passe alors d’un traitement synchrone à un traitement avec jeton d’état, où le client interroge l’API jusqu’à ce que le travail soit terminé. La question à se poser est simple : l’utilisateur a-t-il besoin du résultat pour sa prochaine action, ou peut-il l’obtenir plus tard ?

La latence réseau et le pooling de connexions

Une dernière famille de causes se situe entre le service et ses dépendances : la latence réseau et la gestion des connexions. Chaque appel à une base ou à un service externe paie un coût fixe d’ouverture de connexion, de négociation et de transfert. Quand ces appels se multiplient, ce coût fixe domine.

Le pooling de connexions corrige la partie ouverture : les connexions sont réutilisées plutôt que recréées. Sans pool, chaque requête paie l’ouverture d’une connexion, soit parfois des dizaines de millisecondes ; PgBouncer joue ce rôle devant PostgreSQL.

La latence d’un service situé dans une autre région est incompressible. Ce qui se corrige, c’est le nombre d’allers-retours. Réduire les appels, regrouper les opérations, rapprocher les dépendances : autant de moyens de limiter le poids de la distance.

Par où commencer pour accélérer votre API

Le scénario le plus courant qu’on rencontre est un produit qui allait très bien avec cent utilisateurs, puis qui ralentit à mesure que les données et le trafic grandissent, sans que personne ne sache quelle couche est en cause.

Dans ce cas, on commence par brancher le traçage et lister les causes réelles, avant de toucher au code. C’est le point de départ de l’audit de reprise de produit : en 3 jours et pour 750 €, on mesure ce qui ralentit votre API, avec la sécurité et l’architecture, et vous repartez avec un plan de stabilisation chiffré au forfait.

Parlons de votre projet.

Échange gratuit de 30 minutes. On vous dit ce qui est faisable, ce que ça coûte, et si l'IA est rentable dans votre cas.

En 30 minutes avec un lead technique, vous repartez avec :

  • Un avis franc sur la faisabilité de votre cas, et la façon de s'y prendre.
  • Une fourchette de budget : construction et coût mensuel de l'IA.
  • Le gain attendu et le délai pour que l'agent se rembourse.
  • Le premier pas le plus simple, même si ce n'est pas avec nous.
Prendre rendez-vous

Gratuit, sans engagement, sans relance commerciale.