Comment faire des tests de charge pour les API

Comment faire des tests de charge pour les API
Gerónimo
Gerónimo
Fractional CTO
21 min read

Si vous avez deja developpe une application web concue pour gerer un volume important d’utilisateurs, vous avez ete confronte a la question de determiner les ressources dont votre application a besoin pour gerer le trafic attendu avec les niveaux de service souhaites. Les tests de performance et de charge vous permettent de comprendre comment votre application se comportera dans differents scenarios d’utilisation en repondant aux questions suivantes :

  • Combien de ressources (CPU, RAM, disque, bande passante, GPU, etc.) mon application consomme-t-elle pour traiter le trafic ?

  • Quelle infrastructure me faut-il pour repondre au trafic attendu ?

  • Quelle est la vitesse de mon application ?

  • A quelle vitesse mon infrastructure se met-elle a l’echelle ? Quel impact la mise a l’echelle a-t-elle sur les utilisateurs ?

  • Les performances sont-elles stables ou se degradent-elles avec le temps ?

  • Quelle est la resilience de mon application face aux pics de trafic ?

  • Comment les performances de mon application evoluent-elles avec l’introduction de nouvelles fonctionnalites ?

L’objectif de cet article est de fournir des outils pour repondre a ces questions pour votre application. Nous commencerons par une introduction theorique aux tests de performance et de charge, puis nous passerons a une seconde partie pratique ou nous verrons comment effectuer des tests de charge sur une API a partir d’un projet exemple.

Strategie de test (Partie theorique)

Avant d’aborder la creation du plan de test, vous devez analyser comment l’API est definie et comment elle sera utilisee en production pour determiner comment mener les tests.

Dans ce cas specifique, nous allons tester l’API d’une application web pour un Blog. Cette API se compose de plusieurs endpoints pour la gestion des utilisateurs et des articles. Considerations :

  • Comme chaque endpoint a une logique metier differente, leurs performances et le debit qu’ils supportent devraient etre differents.

  • Les tests doivent etre bases sur le nombre attendu d’utilisateurs pour notre application. Il n’est pas logique de tester avec 100 000 utilisateurs simultanes si notre application ne depassera probablement pas 100.

  • Premierement, il est recommande de tester chaque endpoint separement pour comprendre les limites et capacites de chacun de maniere isolee. Comme etape suivante, tester avec des schemas d’appels (vers differents endpoints) qui reproduisent des cas d’utilisation reels (par exemple, un utilisateur se connecte, puis liste les articles, recupere 2 ou 3 articles specifiques, etc.).

  • Si l’application n’est pas encore en production, nous devrons creer des tests bases sur des hypotheses que nous pensons pouvoir representer la realite. Une fois l’application deployee en production, nous pourrons utiliser les donnees d’utilisation reelles pour mettre a jour les tests.

  • Si le systeme dispose d’un auto-scaling, le test permettra de tester l’auto-scaling et de comprendre sa vitesse, les erreurs entre les evenements d’auto-scaling, etc. Dans ce cas specifique, l’application que nous allons tester ne dispose pas d’auto-scaling.

Que mesurer

  • Utilisation des ressources : CPU, RAM, trafic reseau, …

  • Latence des appels : la latence de l’appel (y compris la reponse) a chaque endpoint de l’API. Il existe differentes facons de mesurer la latence ; les percentiles sont normalement utilises. Par exemple, si p95 (ou 95e percentile) est de 85 ms, cela signifie que 95 % des appels se terminent en au plus ce temps.

  • Debit, mesure comme le nombre d’appels a un endpoint par seconde (RPS ou requests-per-second) que le backend accepte dans differentes conditions.

  • Taux d’erreur ou nombre d’appels qui repondent avec une erreur par rapport au nombre total d’appels.

Types de tests de performance

Au sein des tests de performance, differents types se distinguent en fonction de la charge ou du volume de donnees. L’objectif est de representer differentes situations d’utilisation que notre systeme peut rencontrer en production :

  • Tests de reference ou tests moyens. Ils permettent de comprendre comment l’API se comporte avec un nombre d’appels que nous considerons normal. Dans notre exemple, nous considererons que dans des conditions normales, nous aurons 20 utilisateurs simultanes faisant des requetes a l’API.

  • Tests de charge. Ils nous permettent de comprendre comment l’API repond lorsque des pics d’utilisation attendus se produisent. Par exemple, si nous avons calcule que pendant les heures de pointe nous aurons 50 utilisateurs faisant des requetes a l’API, le test reproduira un schema de trafic qui atteint ce pic.

  • Tests de stress. Ils permettent de comprendre la capacite maximale de notre API (mesuree en RPS, requetes par seconde) avec l’infrastructure actuelle, comment l’auto-scaling se comporte (si disponible), et comment les performances se degradent (latence) et le taux d’erreur augmente (en cas de capacite fixe) a mesure que le trafic augmente. Quelques exemples de situations qui pourraient stresser un systeme seraient le Black Friday dans le commerce electronique ou un evenement sportif dans un service de livraison de nourriture.

  • Tests de pic. Ils permettent de voir comment le systeme se comporte face a des pics de trafic sporadiques. Et de voir combien d’appels nous pouvons traiter correctement et combien avec des erreurs. Ils permettent egalement de verifier si le service est resilient et reste actif ou au contraire plante. Dans le monde reel, ces pics peuvent survenir pour differentes raisons, par exemple si quelqu’un de populaire ecrit un tweet referencant notre site web et que de nombreuses visites se produisent simultanement (egalement connu sous le nom de “HackerNews hug of death”).

  • Tests d’endurance (Soak testing). Ils permettent de comprendre le comportement de l’API sur des periodes prolongees, pouvant durer des jours ou des semaines. Ils visent a verifier s’il y a des degradations du systeme qui pourraient affecter le service a moyen-long terme. Par exemple, si nous avons une petite fuite memoire dans l’application, il pourrait falloir des jours pour consommer toute la RAM allouee, ce qui provoquerait probablement un redemarrage du service et l’echec de tous les appels que le service traitait a ce moment-la (et les appels qui se produisaient pendant le temps jusqu’a ce que le service soit de nouveau disponible, s’il n’y a pas d’autres instances de service disponibles pour absorber le trafic).

Objectifs et plan (Partie pratique)

Par souci de brievete, nous nous concentrerons sur les tests de reference et les tests de stress. Cependant, il n’est pas complique de concevoir des tests de charge et d’endurance a partir des informations que nous partagerons.

Pour eviter d’allonger trop l’article, les tests consisteront a tester un seul endpoint (liste des articles). Laissant au lecteur la tache d’elargir et d’adapter les tests a son application et a ses cas d’utilisation specifiques.

Le plan sera le suivant :

  1. Description du stack et du projet de test
  2. Description de l’environnement
  3. Deploiement de l’environnement
  4. Tests de reference
  5. Tests de stress
  6. Notes finales

1 — Description du stack et du projet de test

Pour l’execution des tests, nous avons decide de creer un backend en GO qui implemente une API REST simple et utilise une base de donnees MariaDB pour la persistance des donnees. Le code ainsi que les instructions de deploiement se trouvent ici :

https://github.com/gerodp/blog-sample-backend-go-grafana

Note : Il s’agit d’un backend de test a usage illustratif uniquement et n’est pas destine aux environnements de production.

D’autre part, nous avons cree un autre depot avec differents tests, que nous expliquons ci-dessous :

https://github.com/gerodp/blog-sample-perf-test-k6-grafana

Stack

  • Backend d’API REST en GO avec les bibliotheques GIN (serveur HTTP) et GORM (ORM)
  • Outil de test de charge : Grafana K6.
  • Supervision du systeme avec Prometheus et Grafana
  • Base de donnees MariaDB
  • Execution et orchestration avec Docker et Docker Compose

A propos de Grafana K6 — Outil de test de charge

K6 est une solution Open Source developpee par Grafana Labs. Nous l’avons selectionnee car elle est facile a utiliser, prend en charge tous les types de tests de performance, s’integre bien avec les outils de supervision Grafana et Prometheus, et dispose d’une excellente documentation en plusieurs langues, dont l’espagnol.

Cependant, il existe un grand nombre d’outils de ce type qui pourraient egalement etre utilises, tels que : JMeter, Locust, Taurus, Artillery, ou d’autres.

2 — Description de l’environnement

Par souci de simplicite, nous deploierons le backend qui implemente l’API sur une AWS EC2. Ce type de deploiement est tres simple et n’est pas destine aux environnements de production ; dans ces cas, il est recommande d’explorer d’autres solutions comme le deploiement en cluster ou d’autres alternatives.

Dans le README du depot nous pouvons lire les etapes pour l’installer sur une EC2 ou une machine Linux compatible.

3 — Deploiement de l’environnement

Dans le cadre du test, nous avons 2 composants differencies : 1) le backend qui implemente l’API et 2) les tests de charge K6

Deploiement de l’implementation du backend API

1 — Nous lancons une AWS EC2 avec Linux. Dans notre cas, nous l’avons testee sur un t3.large et m5.large avec Ubuntu, mais d’autres instances plus petites fonctionnent parfaitement (le demarrage du backend prendra juste un peu plus de temps en raison de la compilation Go). Et nous devrons lui attribuer une adresse IP publique pour y acceder depuis l’exterieur.

2 — Dans le Security Group, nous ajoutons 2 regles de trafic entrant aux ports 22 (SSH) et 9494 (port ou l’API est exposee) depuis notre IP domestique ou la machine d’ou nous lancerons les tests K6.

3 — Nous nous connectons via SSH a la machine et executons les commandes suivantes (dans le README) :

https://github.com/gerodp/blog-sample-backend-go-grafana#deployment-in-aws-ec2

4 — Nous pouvons ouvrir un tunnel SSH pour acceder a Grafana avec cette commande :

ssh -i "/path/to/pemfile" -N ubuntu@<PUBLIC_IP> -L 8800:localhost:3000

5 — Et nous allons sur http://localhost:8800 avec un navigateur pour ouvrir Grafana.

Deploiement des tests

Nous pouvons executer les tests directement sur notre machine si le systeme que nous allons tester est petit, ou lancer une infrastructure dediee lorsque le systeme est plus grand. K6 dispose d’un Kubernetes Operator qui le permet. Pour cet article, nous les lancerons depuis notre machine par souci de simplicite (dans ce cas, un Mac avec puce M1).

1- Cloner le depot :

https://github.com/gerodp/blog-sample-perf-test-k6-grafana

2- Lancer un test en executant cette commande avec make :

API_URL=http://EC2_PUBLIC_IP:9494 TEST=testfile.js make start

La commande lance plusieurs conteneurs :

  • Un conteneur avec K6 qui execute le test specifie dans testfile.js, et ecoute les changements dans ce fichier pour le relancer a chaque sauvegarde
  • Un conteneur avec Prometheus et un autre avec Grafana pour la supervision

3- Ouvrir Grafana dans un navigateur en visitant http://localhost:3000

4- Nous pouvons terminer l’execution du conteneur de test, car nous les relancerons dans la section suivante avec un test specifique.

Note : Comme nous pouvons le voir, nous avons 2 instances Grafana, 1 pour l’API (avec les metriques d’utilisation des ressources du backend API) et une autre pour les Tests (avec les metriques que K6 genere sur l’execution des tests : debit, latences, taux d’erreur, etc.). A partir de maintenant, nous ferons reference a chaque instance Grafana en precisant s’il s’agit de celle des Tests ou de l’API.

4 — Tests de reference

Supposons que dans des conditions normales, notre Blog aura environ 20 utilisateurs simultanes qui font un appel a l’API de liste des articles par seconde (c’est un scenario fictif, car le schema de trafic reel sera probablement different, mais il sert d’illustration).

Si nous allons au depot avec les tests K6 et ouvrons le fichier :

Nous verrons le contenu suivant :

import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
 thresholds: {
   http_req_failed: ['rate<0.01'], // http errors should be less than 1%
   http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
 },
 scenarios: {
   read_posts_constant: {
     executor: 'constant-arrival-rate',

     // Our test should last 10 minutes in total
     duration: '600s',

     // It should start 20 iterations per `timeUnit`. Note that iterations starting points
     // will be evenly spread across the `timeUnit` period.
     rate: 20,

     // It should start `rate` iterations per second
     timeUnit: '1s',

     // It should preallocate 55 VUs before starting the test
     preAllocatedVUs: 55,

     // It is allowed to spin up to 80 maximum VUs to sustain the defined
     // constant arrival rate.
     maxVUs: 80,
   }
 }
};

//This function runs only once per Test
//and performs a login
export function setup() {
 let loginParams = { username: 'testint1', password: 'testint1'};

 let loginRes = http.post(__ENV.SERVICE_URL+'/login', JSON.stringify(loginParams), {
   headers: { 'Content-Type': 'application/json' },
 });
 check(loginRes, {
   "status is 200": (r) => r.status == 200,
 });

 return { token: loginRes.json().token };
}


export default function(data) {
 const token = data.token;

 let resp = http.get(__ENV.SERVICE_URL+"/auth/post?page_size=5",{
   headers: {
     'Content-Type': 'application/json',
     'Authorization': 'Bearer ' + token,
    },
 });

 check(resp, {
   "status is 200": (r) => r.status == 200,
 });

 sleep(1);
}

Nous n’expliquerons pas tous les details du code, car ils peuvent etre consultes dans l’excellente documentation k6. Mais commentons les parties les plus importantes :

thresholds: {
   http_req_failed: ['rate<0.01'], // http errors should be less than 1%
   http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
 },

K6 permet de definir nos SLO (Service level objectives) directement dans le code. Pour notre test, nous avons defini que nous voulons que la latence au 95e percentile soit inferieure a 200 ms et que le taux d’erreur soit inferieur a 1 %. Si l’un des SLO n’est pas respecte, K6 l’indiquera dans le rapport de resultats affiche a la fin de l’execution du test.

 executor: 'constant-arrival-rate',

 // Our test should last 10 minutes in total
 duration: '600s',

 // It should start 20 iterations per `timeUnit`. Note that iterations starting points
 // will be evenly spread across the `timeUnit` period.
 rate: 20,

 // It should start `rate` iterations per second
 timeUnit: '1s',

Puisque nous voulons un taux d’appels constant par seconde, nous choisissons cet executeur qui garantit le demarrage de ‘rate’ iterations par ’timeUnit’. Pour en savoir plus sur les executeurs disponibles, nous pouvons consulter la documentation K6.

Pour le lancer, nous executons la commande suivante :

API_URL=http://EC2_PUBLIC_IP:9494 TEST=baseline_test.js make start

Apres 10 minutes, nous obtiendrons le resultat du test dans les logs :

La ligne ‘checks’ dans le rapport nous indique que 100 % des verifications ont reussi.

‘http_req_duration’ nous montre la latence des appels (mesuree depuis le client K6 ; notez que la latence sera fortement proportionnelle a la distance entre la machine ou le client K6 lancant le test s’execute et la machine ou le systeme teste s’execute). Le p(095) ou 95e percentile est de 135,53 ms, ce qui signifie que 95 % des appels se sont termines en au plus ce temps. C’est en dessous du SLO que nous avons defini de p95<200 ms. D’autre part, la latence moyenne est de 105,28 ms.

Si nous allons dans le Grafana des Tests (http://localhost:3000) et ouvrons le tableau de bord Test Result, nous pouvons voir les courbes avec les RPS, les VUs actifs (Utilisateurs Virtuels K6) et le temps de reponse moyen (latence moyenne)

Comme on peut l’observer, le RPS (courbe orange en pointilles) s’est maintenu a 20 RPS, comme nous l’avons specifie dans le test. Le temps de reponse moyen (courbe verte), bien qu’il soit vrai qu’a premiere vue il montre un changement plus important au debut puis devient plus ou moins constant, la difference entre la valeur moyenne maximale et minimale est inferieure a 10 %, ce qui est conforme aux attentes. En general, de petites variations dans les mesures sont attendues car de nombreux facteurs peuvent affecter les temps, de la charge du systeme au moment du test a l’etat du reseau.

D’autre part, nous pouvons voir qu’aucune erreur ne s’est produite, ou en d’autres termes, le taux d’erreur a ete de 0 %, ce qui signifie que nous avons respecte l’autre SLO qui etablissait que le taux d’erreur devait etre inferieur a 1 % des appels.

Jusqu’ici, tout semble indiquer que l’API se comporte comme prevu, sans erreurs et avec une latence de reponse constante. Cela n’est pas concluant quant au fait qu’il ne puisse pas y avoir d’autres problemes qui pourraient affecter l’avenir. Pour cela, nous sommes interesses a verifier que l’utilisation des ressources CPU et RAM des services est adequate et ne montre pas de tendances a la hausse qui pourraient signaler un probleme futur.

Si nous allons dans le tableau de bord grafana Cadvisor exporter, nous trouvons les metriques d’utilisation des ressources. Dans le premier graphique, nous pouvons observer la consommation CPU pour differents services. Comme on peut le voir, l’utilisation du CPU est tres faible pour les deux services, avec une legere augmentation au debut du test, puis elle se stabilise.

L’utilisation de la memoire est de 18,4 Mo pour le backend et de 96,9 pour MariaDB, et les courbes restent plates.

Avec ces verifications, il semble que le systeme se comporte de maniere stable en termes de performance, et sans indicateurs qu’un probleme pourrait survenir avec 20 utilisateurs simultanes et le schema d’utilisation defini dans le test. Cependant, pour avoir une plus grande certitude que le systeme se comporte de maniere stable sur des periodes plus longues, il est recommande de faire des tests d’endurance.

Selon les technologies que nous utilisons, nous pouvons etendre la supervision a davantage de metriques. Par exemple, si notre base de donnees est MySQL ou MariaDB, nous pouvons utiliser un exporteur Prometheus qui expose un grand nombre de metriques, du nombre de connexions actives a la latence des requetes, et elles sont utiles pour connaitre la charge du systeme plus en detail. Sur cette page nous pouvons trouver une liste detaillee des exporteurs Prometheus pour la collecte de metriques selon la technologie.

Ensuite, nous allons proceder aux tests de stress pour voir comment l’API se comporte lorsque la charge est beaucoup plus elevee.

5 — Tests de stress

Comme nous l’avons observe dans le test precedent, avec 20 utilisateurs le systeme se comporte comme prevu. Nous pouvons commencer avec 25 RPS, par exemple, et continuer a augmenter la charge a 50, 100, 150, …. K6 prend en charge plusieurs facons de le faire, mais pour comprendre comment le faire, nous devons d’abord introduire quelques concepts sur K6.

Utilisateurs virtuels (VU) et iterations K6

Dans K6, chaque utilisateur virtuel consiste en une boucle while qui execute la fonction de test que nous avons definie dans le fichier K6 en boucle. Chaque execution de la boucle est appelee une iteration. Si nous definissons 10 VU, nous aurons 10 boucles while executant des iterations en parallele. Un VU n’execute qu’une seule iteration a la fois, et l’iteration suivante ne commence pas tant que la precedente n’est pas terminee. Par consequent, le nombre d’iterations qu’un VU peut executer est defini par la rapidite ou la lenteur avec laquelle le systeme teste repond. Cela signifie que si dans notre test nous voulons reproduire N nombre d’utilisateurs, nous devrons utiliser un executeur de type VU, et si ce que nous voulons est de reproduire N nombre de RPS (requetes par seconde), il est ideal d’utiliser un executeur de type iteration, qui adaptera dynamiquement le nombre de VU pour atteindre les iterations specifiees dans le test. K6 fournit differents types d’executeurs qui determinent comment les tests sont executes. Pour en savoir plus sur les executeurs disponibles, nous pouvons consulter la documentation K6.

Pour ce cas specifique, nous allons utiliser l’executeur Ramping Arrival Rate qui permet de specifier le nombre d’iterations a executer par unite de temps, puisque nous sommes interesses a connaitre la capacite de notre systeme par rapport aux RPS. Puisque nous ne faisons qu’un seul appel dans notre test, le nombre d’iterations sera equivalent aux RPS.

Nous ferons chaque etape de 60 secondes de montee en charge plus 60 secondes avec un taux stable. Il est important de prendre en compte la frequence a laquelle Prometheus echantillonne les donnees ; si le test est trop rapide, Prometheus ne pourra pas capturer correctement les metriques et les changements.

Etape 1 : 0 -> 25 RPS.

Pour atteindre 25 RPS en 60 secondes, je dois executer 25*60 iterations -> 1500 iterations

Etape 2 : 25 -> 50 RPS -> 50*60 = 3000 iterations

etc..

Si nous allons au depot avec les tests K6 et ouvrons le fichier :

import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
  thresholds: {
    http_req_failed: ['rate<0.01'], // http errors should be less than 1%
    http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
  },
  scenarios: {
    read_posts_stress_test: {
      executor: 'ramping-arrival-rate',

      // Our test with at a rate of 50 iterations started per `timeUnit` (e.g minute).
      startRate: 25,

      // It should start `startRate` iterations per second
      timeUnit: '1m',

      // It should preallocate 300 VUs before starting the test.
      preAllocatedVUs: 300,

      // It is allowed to spin up to 1500 maximum VUs in order to sustain the defined
      // constant arrival rate.
      maxVUs: 5000,

      stages: [
        { target: 25*60, duration: '1m' },
        { target: 25*60, duration: '2m' },
        { target: 50*60, duration: '1m' },
        { target: 50*60, duration: '2m' },
        { target: 100*60, duration: '1m' },
        { target: 100*60, duration: '2m' },
        { target: 150*60, duration: '1m' },
        { target: 150*60, duration: '2m' },
        { target: 25*60, duration: '3m' },
      ],
    }
  }
};

//This function runs only once per Test
export function setup() {
  let loginParams = { username: 'testint1', password: 'testint1'};

  let loginRes = http.post(__ENV.SERVICE_URL+'/login', JSON.stringify(loginParams), {
    headers: { 'Content-Type': 'application/json' },
  });
  check(loginRes, {
    "status is 200": (r) => r.status == 200,
  });

  return { token: loginRes.json().token };
}

export default function(data) {

  const token = data.token;

  let resp = http.get(__ENV.SERVICE_URL+"/auth/post?page_size=5",{
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ' + token,
     },
  });

  check(resp, {
    "status is 200": (r) => r.status == 200,
  });

  sleep(1);
}

Pour le lancer, nous executons la commande suivante :

API_URL=http://EC2_PUBLIC_IP:9494 TEST=stress_test.js make start

Apres 15 minutes, nous obtiendrons le resultat du test dans les logs :

Comme on peut le voir dans les resultats, la derniere ligne indique que certains des seuils definis (avec les SLO) ont echoue. La latence p95 est de 28,4 s, ce qui est bien au-dessus des 200 ms marques comme objectif. Cependant, le taux d’erreur de 0,27 % est reste en dessous du 1 % defini comme objectif.

Si nous ouvrons le tableau de bord Test Result dans Grafana, nous pouvons voir dans le graphique l’evolution de la latence a mesure que les RPS augmentent.

Si nous zoomons sur le graphique API Call Response Time, nous voyons le moment ou la latence p95 depasse le seuil de 200 ms (ligne rouge). Si nous observons la valeur RPS dans l’autre graphique a cet instant, nous voyons qu’elle est d’environ 22 RPS. Cela signifie qu’avec l’infrastructure actuelle, nous ne devrions pas depasser cette limite si nous voulons respecter le SLO de latence.

Cependant, au-dela de ce point, le systeme continue de fonctionner sans erreurs (bien qu’avec une latence elevee) jusqu’a atteindre environ 115 RPS, quand certaines erreurs commencent a se produire.

Une autre chose que nous pouvons observer est que les RPS maximaux atteints sont d’environ 138, bien que notre objectif etait d’atteindre 150 RPS. Cela se produit parce que la latence augmente tellement que le nombre maximum de VU n’est pas suffisant pour atteindre les RPS specifies. Ici, nous pourrions augmenter le nombre maximum de VU dans le test, mais nous devons considerer que la machine a partir de laquelle le test est lance a une capacite suffisante pour le supporter. Dans un systeme plus grand, les tests pourraient etre lances depuis un cluster et le nombre de conteneurs pourrait etre mis a l’echelle. En tout cas, avec les RPS atteints, c’est suffisant pour nous de voir que le systeme commence a se degrader et a renvoyer des appels avec des erreurs, bien qu’il ne plante pas. Et quand le trafic revient a des niveaux normaux, le systeme repond de nouveau dans les seuils definis.

D’autre part, si nous ouvrons le tableau de bord Grafana de l’API, nous pouvons verifier que la memoire et le CPU ont augmente par rapport a ce qui a ete observe dans le test de reference, mais meme sous des charges elevees, les courbes restent plates, ce qui indique que nous n’avons pas de problemes de fuite memoire ou similaires pour la fonctionnalite testee.

Comme prochaines etapes possibles, le lecteur pourrait investiguer ou se trouvent les goulots d’etranglement qui causent l’augmentation de la latence a partir de certains RPS et pourquoi des erreurs se produisent qui font que l’API ne repond pas avec le code 200.

6 — Notes finales

Dans cet article, nous avons introduit des concepts theoriques sur la facon de definir une strategie de tests de charge et de performance, puis nous avons montre quelques exemples de comment effectuer certains de ces tests sur une application qui implemente une API. Bien que nous nous soyons concentres sur les API, ces tests sont extrapolables a d’autres systemes dont la charge est variable.

Nous esperons que le lecteur sent qu’il dispose de plus d’outils pour repondre aux questions que nous avons posees au debut :

  • Combien de ressources (CPU, RAM, disque, bande passante, GPU, etc.) mon application consomme-t-elle pour traiter le trafic ?

  • Quelle infrastructure me faut-il pour repondre au trafic attendu ?

  • Quelle est la vitesse de mon application ?

  • A quelle vitesse mon infrastructure se met-elle a l’echelle ? Quel impact la mise a l’echelle a-t-elle sur les utilisateurs ?

  • Les performances sont-elles stables ou se degradent-elles avec le temps ?

  • Quelle est la resilience de mon application face aux pics de trafic ?

  • Comment les performances de mon application evoluent-elles avec l’introduction de nouvelles fonctionnalites ?

Le type de tests que nous implementons pour notre systeme final dependra beaucoup de la nature du systeme, de l’utilisation attendue et de l’infrastructure.

A propos de moi

  • Au cours des 4 dernieres annees, j’ai travaille en tant que CTPO d’une startup qui developpe des produits bases sur l’IA et la vision par ordinateur pour divers secteurs tels que le commerce de detail, la construction, les medias et les transports.

  • J’ai participe a la conception de differents produits, leur developpement et deploiement en production pour des clients dans 8 pays d’Europe, du Moyen-Orient et des Etats-Unis.

  • J’ai dirige la scalabilite et la transformation de l’equipe, passant d’un groupe initial de 4 ingenieurs a un departement de 25 professionnels, incluant des developpeurs, des data scientists, des devops et des customer success managers.

  • Auparavant, j’ai travaille en tant qu’architecte principal et ingenieur logiciel pour differents clients (Vodafone, LaLiga, Orange - Optiva Media) et de grandes entreprises comme Amadeus.

  • Actuellement, je travaille en tant que Fractional CTO aidant les startups et les entreprises a tout stade qui ont des besoins et des problemes avec la strategie technologique et produit, la productivite des equipes et la promotion des ingenieurs a des postes de management.

Si vous souhaitez explorer comment un Fractional CTO peut vous aider avec des aspects specifiques de votre entreprise/startup, vous pouvez planifier un appel.

Blog API tests de charge perftest tests