AWS Lambda - Les leviers d’optimisation
AWS Lambda - Les leviers d’optimisation

AWS Lambda - Les leviers d’optimisation

Cet article est un complément à notre vidéo du même nom que vous pouvez retrouver sur notre chaîne Youtube juste ici. Dans cette vidéo, nous abordons les différents facteurs influençant la performance des fonctions lambdas et quels sont les leviers à notre disposition.

Notre approche a été d’aborder successivement chaque étape du cycle de vie d’une lambda en illustrant à chaque fois quelques moyens d’optimisations disponibles. Voici un aperçu de ces différentes étapes :

image

Résultats de nos tests de performances

Nous avons réalisé différents tests de performances pour mettre en lumière l’impact de certain choix de configuration sur la durée d’exécution et le temps d’initialisation de fonction lambda.

Vous trouverez ci-dessous la version détaillée de ces résultats ainsi que des explications sur nos protocoles de tests.

Temps d’initialisation du runtime

Le but de ce test était de mesurer le temps nécessaire pour initialiser une fonction lambda dans les différents langages nativement supportés par AWS lambda lors d’un démarrage à froid.

Nous avons utilisé AWS X-Ray pour mesurer le temps d’initialisation globale de nos fonctions lambdas. Ce temps inclut donc :

  • Le temps de provisionnement de la microVM
  • Le téléchargement du package
  • L’initialisation des extensions
  • L’initialisation du runtime
  • L’initialisation de la fonction

Afin de limiter l’impact sur nos mesures de temps d’initialisation du runtime, nous avons réduit au maximum les délais de chacune des autres étapes d’initialisation.

Pour le téléchargement du package, nous avons créé des fonctions lambdas ne contenant que le handler sans extensions internes ou externes et un simple retour HTTP 200, permettant ainsi de limiter la taille du package au strict minimum.

Voici les résultats que nous avons obtenus :

image

Il apparaît clairement que le cold start d’une fonction peut varier du simple au double en fonction du runtime qui est choisi.

Temps d’exécution à chaud

Pour la suite de nos tests, nous avons modifié le code de nos lambda pour leur appliquer une logique de traitement semblable à ce que l’on retrouve dans de nombreux processus métier. Il s’agit de parcourir un JSON reçu via l’évènement de déclenchement et d’inscrire chacun des valeurs dans une table Dynamodb.

Dans notre exemple, ce JSON contient une liste de 250 pays et les appels aux API dynamodb sont fait en utilisant les points de terminaisons publics.

Voici les résultats que nous avons obtenus lors de l’exécution de cette logique sur des fonctions pré-initialisées avec une configuration mémoire de 128 Mo :

image

Ici aussi l’écart de performance est flagrant. On atteint en prenant les extrêmes un écart de x20 entre NodeJS et Go.

Nous avons également effectué la même série de tests, mais avec une configuration mémoire de 10 Go et voici les résultats :

image

L’augmentation de la mémoire allouée, et intrinsèquement du nombre de vCPU, permet de réduire considérablement les temps d’exécution des langages interprétés. Cela leur permettant d’atteindre un ordre de grandeur plus proche de celui des langages compilés.

Pour l’exemple, nous avons effectué ces tests avec les configurations minimales et maximales pour bien visualiser l’impact sur le temps d’exécution d’une logique métier simple. Bien évidement, le temps d’exécution n’étant pas simplement inversement proportionnel à la quantité de mémoire allouée, un juste milieu existe dans cet intervalle. Il convient alors de déterminer où placer le curseur en fonction des besoins de performance et du coût d’exécution.

Sources/Documentation

Outil de tests automatisé des différentes configurations mémoire :

Runtime AWS Lambda :

Cycle de vie des fonctions AWS Lambda :

AWS Lambda extensions :

AWS Lambda Snapstart :

AWS Lambda Provisionned Concurrency :

Firecracker :

Merci pour votre lecture. Si cet article vous a plu, merci de le partager sur vos réseaux 😉

Timothée Taron - février 13, 2024

image