8 astuces pour doper la performance de vos APIs

Pragmatic Nerdz
Aug 4, 2023 - 5 Minutes

Êtes-vous frustré par la lenteur de vos APIs qui ralentissent vos applications? Nous allons vous partager 8 astuces d'optimisation qui vont vous permettre d'améliorer la performance de vos API par un facteur de 10.

Avant de commencer, il est important de souligner que l'optimisation ne doit pas être la première étape dans votre processus de développement, l'optimisation ne doit être faite qu'après avoir confirmé avec des données quels sont les problèmes de performance. Toute optimisation prématurée va conduire à accroître inutilement la complexité de votre système.

1. Utilisez une Cache

Cette technique est l'une des façons les plus efficaces pour accélérer vos APIs. On utilise une cache pour stocker les résultats de calculs coûteux, comme ça on peut les retourner plus tard sans avoir à refaire les calculs coûteux.

Si vous avez des requêtes qui produisent toujours les même réponses, vous pouvez utiliser une cache comme Redis ou Memcached pour y stocker les réponses, ce qui limitera les accès à la base de données.

Votre code ressemblera à:

if redis.contains(query)
  return redis.get(query)
else
  result = database.select(query)
  redis.put(query, result)
  return result
end

2. Paginez les réponses

Retourner une large quantité d'items (Ex: la liste de tous les articles d'un blog) va ralentir votre API à cause de la latence due au transfert réseau.

Pour limiter ce problème, on retourne les données par page. Chaque page contenant un nombre d'items fixe, ce qui réduit considérablement la quantité de données à retourner.

Receive my Stories your e-mail inbox as soon as I publish them.
Subscribe to my Blog

Pour paginer les données, le client ajoute dans sa requête les paramètres limit et offset:

  • limit indiquant le nombre d'item dans chacune des page
  • offset indiquant l'index du 1er item a retourner

3. Optimisez la sérialisation

La processus de sérialisation consiste à encoder vos objets de données dans un format pour le transfer réseau.

  • Utilisez JSON au lieu de XML car il est plus compact. JSON peut représenter les mêmes données que XML dans une taille de fichier plus petite.
  • Pour plus de performance, vous pouvez opter pour des formats binaires tels que Protobuf ou Avro qui sont encore plus compacts et performants que JSON.

4. Compressez les réponses

Une fois les données sérialisées,  compresser-les afin réduire leur taille pour accélérer le transport réseau. Le client reçoit les données compressées, les décompresse avant de les utiliser.

GZIP est l'algorithme largement utilisé pour les compressions de données. Mais vous pouvez aussi utilisé Brotli pour plus de performance (15 à 20% plus performant que GZIP).

5. Utilisez les traitement asynchrones

Les communications entre client et API sont généralement de façon synchrone: le client envoie une requête à l'API et attend que l'API complète le traitement de la réponse avant de faire une autre tâche. Si le temps de traitement est très long, le client va rester en attente pendant longtemps.

Avec les traitements asynchrone, le client n'a pas à attendre que l'API complète le traitement de ses requêtes, comme ca il peut effectuer d'autres tâches.

Pour effectuer des traitements asynchrones, on insère entre le client et l'API un Message Broker comme RabbitMQ ou Kafka:

  1. Le client envoie la requête au Message Broker, et ensuite peux continuer à effectuer d'autre tâches
  2. Le Message Broker envoie en arrière-plan la requête à l'API pour traitement. Même si le temps de traitement par l'API est long, le client n'est pas impacté car il n'est pas en attente 

6. Optimisez l'accès à la base de données

Les requêtes SQL inefficaces peuvent dégrader de manière significative la performance de vos APIs. Il est important d'identifier les requêtes les plus lentes, puis ajouter les index pour les optimiser.

Identifiez aussi les requêtes N+1, qui surviennent lorsque l'application récupère les données en plusieurs requêtes, au lieu d'une seule (ou deux). C'est un problème récurrent avec l'utilisation des ORM (Object Relational Mapping) tels que Hibernate ou Doctrine.

Voici un exemple de code qui illustre le problème des requêtes N+1

// CODE
class Post{
  ...
  val comments: List<Comment>
}
class Comment{
  ...
}

val post = database.select(query)
foreach comment in post.comments{
   ...
}   

// SQL produite par l'ORM
select * from POST where post_id=
select * from COMMENT where comment_id=1
select * from COMMENT where comment_id=2
...
select * from COMMENT where comment_id=N

Ce code produit N+1 requêtes:

  • 1 requête pour charger 1 POST
  • N requêtes pour charger les N COMMENT

Il faudrait plutôt configurer votre ORM pour qu'il charge tous les COMMENT associés à un POST en 1 seule requête.

select * from POST where post_id=..
select * from COMMENT where post_id=..

7. Optimisez votre Garbage Collector (GC)

Plusieurs langage de programmation (.NET, Java, Go, Javascript, PHP) offrent des Garbage Collector,  qui enlève au développeur la responsabilité de s'occuper de la gestion et du recyclage de la mémoire (comment avec les languages comme C ou C++).

Lors de l'allocation de la mémoire, le GC utilise 2 zones:

  • Young area: C'est là où les nouveaux objets sont créés. Lorsque cette zone est remplie, il y a un processus très rapide de recyclage qui est enclenché pour libérer la mémoire.
  • Old area: Les objets qui survivent au recyclage de la young area sont transférés ici. Le recyclage de cette zone est beaucoup plus lent (plusieurs secondes), et suspend tous les autres processus (Stop the World)! Durant le recyclage de la old area, votre API va être gelée, et ne répondra à aucune requête des clients!

Pour optimiser votre GC, il faut configurer l'allocation de mémoire afin que vos objets ne passent jamais de la young à la old area pour ne pas être pénalisé par le Stop the World causé par le recyclage de la old area

L'optimisation du GC requiert une solide expertise dans le language de programmation, et ne doit être faite après que les optimisations 1 à 6 ont été complétées. 

8. Équilibrez la charge

Lorsque le nombre de requêtes vers votre API devient trop élevé, on peut augmenter la capacité en roulant plusieurs instances de l'API. 

Par exemple, si votre API reçoit 1000 requêtes/seconde alors que la capacité maximale de votre API est de 100 requêtes/seconde, roulez 10 instances de l'API et un Load Balancer pour distribuer les requêtes entre 10 instances.


L'optimisation des API est un processus continu qui implique différentes stratégies et techniques à différentes couches de vos applications. La mise en œuvre de ces techniques se traduit par un temps de réponse plus rapide et une meilleure expérience utilisateur.

Notez qu'il est très important de toujours surveiller votre application pour vraiment comprendre où se situent les goulots d'étranglement afin d'appliquer les techniques appropriées.


Télécharchez votre aide mémoire de performance

PDF
8 Astuce de Performance - Aide Memoire.pdf
106.7 Kb
Performance
Api
Optimisation