Load testing en 5 minutes avec Vegeta

Load testing en 5 minutes avec Vegeta

Le load testing c’est le fun en tabarnak. Mettre des grands coups sur ton application et voir comment elle encaisse c’est le bien. Tu as cinq minutes devant toi ? Il faut que te présente Vegeta !



C’est qui ?

Il y a peu de temps, j’ai dû sortir une API qui allait être tapée assez violemment. D’habitude, et comme à chaque fois, je sors l’énorme framework Locust. Avec toutes les config, toutes les options et les scénarios: je peux tout faire avec. Mais cette fois, je voulais un truc simple et rapide.

Mon objectif est de valider en cinq minutes qu’une application allait tenir une charge importante. Et ça, en faisant d’abord un burst violent puis un flow constant de requêtes. Facile à utiliser et avec un minimum de statistiques : faites place à Vegeta.



vegeta


Vegeta est un outil de load testing écrit en Go pour les services HTTP. Son utilisation est extrêmement simple. En une seule ligne de commande tu peux load tester n’importe quels services HTTP. Tu peux aussi le faire de façon programmatique. Mais on ne va pas parler de ça aujourd’hui. T’as que cinq minutes devant toi, on va se concentrer sur la ligne de commande. Trêve de blabla il est temps de mettre tes mains dessus.



Comment je lui parle ?

On va commencer par l’installer, tu peux le faire de cette façon-là sous Linux :



  • Étape 1 : Installe Vegeta
# téléchargement via CURL
curl -LO https://github.com/tsenart/vegeta/releases/download/v12.7.0/vegeta-12.7.0-linux-amd64.tar.gz

# décompression du tar
tar -zxvf vegeta-12.7.0-linux-amd64.tar.gz

# move le bin dans le /usr/bin
sudo mv ./vegeta /usr/bin/vegeta

# vérification de l'installation
vegeta --version


  • Étape 2 : Liste les cibles dans un fichier texte (targets.txt)
GET http://localhost:8080/path/to/first/route
GET http://localhost:8080/path/to/second/route
GET http://localhost:8080/path/to/third/route

Ici, il faut juste que tu crées un fichier texte. Appelons le targets.txt. Dans ce fichier, on désigne les cibles que Vegeta va tabasser. D’abord le verbe HTTP, puis l’URL. Une cible par ligne. Par souci de simplicité on va seulement taper sur des GET aujourd’hui. Mais sache que n’importe quel type de routes (POST, PUT etc etc) peut être tapé par Vegeta.



  • Étape 3 : Attack !
vegeta attack -targets targets.txt

Et c’est tout ! Tu peux déjà envoyer Vegeta tabasser des gens. Utilise la commande Attack pour lancer le load testing avec l’option targets pour designer le fichier des cibles. Vegeta va attaquer toutes les routes présentes dans ton fichier de façon consécutive et avec un taux de 50 requêtes par secondes par défaut. Il va le faire dans le temps de façon indéfinie tant que tu l’arrêtes pas. Pour faire exactement ce que tu veux, comme tu le veux, il faut que tu lui foutes quelques options.



  • Options utiles

Je te rajoute doucement quelques options pour te montrer comment parler à Vegeta.

L’option targets tu la connais déjà, elle sert à désigner le fichier des cibles HTTP.
L’option header te permet de rajouter un header HTTP à toutes les requêtes.
L’option rate te permet de régler le nombre de requêtes par secondes.
L’option duration te permet de régler le temps de l’attaque en secondes.



vegeta attack -targets=targets.txt -header AppId:c7c734e9 -rate=20 -duration=30s


Cette commande-ci va dire à Vegeta de taper toutes les routes dans ton fichier avec un header HTTP et un taux de requêtes de 20 attaques par secondes durant 30 secondes pour un total de 600 requêtes. Plutôt simple hein ?

Et tout ça c’est bien beau pour comprendre comment ça fonctionne. Mais dans la vraie vie, tu en veux plus. Tu veux un Vegeta plus violent et tu veux des statistiques.



Cas réel avec statistiques

Retour à mon API dont je te parlais au début. Pour cette API on me demande de tenir une charge d’au moins 500 requêtes par seconde. On me demande également un petit rapport avec le temps de réponse moyen. C’est parfait, Vegeta fait très bien les deux.

Pour les statistiques on va coupler la commande Attack avec la commande Plot. La commande Plot va générer automatiquement une page HTML avec un graphique de statistiques complet de l’attaque. Plus précisément, on va rediriger le résultat de l’attaque dans un fichier bin. Ensuite on va piper ce fichier bin dans la commande plot qui va rediriger le tout dans un fichier HTML.

Pour commencer, je vais envoyer Vegeta mettre des claques tout doucement à 300 requêtes/seconde sur 25 secondes juste pour voir comment ça réagit.



vegeta attack -targets=targets.txt -header AppId:c7c734e9 -name=300qps -rate=300 -duration=25s > results.300qps.bin;cat results.300qps.bin | vegeta plot > plot.300qps.html
load testing


Et comme tu peux le voir, mon API est bien toute moisie. Le graphe me montre bien que l’API se casse la gueule tout de suite. Les requêtes dans les premières secondes ne font qu’augmenter les temps de réponse jusqu’à l’implosion au bout de seulement 5 secondes. C’est exactement pour ce genre de surprise que tu devrais toujours faire du load testing.

Du coup, je cherche mon problème et je le trouve : la base de données prend trop cher et le cache n’a pas le temps de se faire que tout se casse la gueule. Je décide d’optimiser mes requêtes et de rajouter un système de queue pour que toutes les requêtes ne tapent pas la base de données en même temps. Une fois ça fait, je recommence l’attaque avec la même commande.



vegeta attack -targets=targets.txt -header AppId:c7c734e9 -name=300qps -rate=300 -duration=25s > results.300qps.bin;cat results.300qps.bin | vegeta plot > plot.300qps.html
load testing


Bingo ! Avec la même charge cette fois je monte seulement à 500 ms dans les premières millisecondes avant de retourner à des temps de réponse acceptables sur tout le reste. La base de données a survécu à la charge grâce à mon système de queue et ensuite le cache prend le relais ! Parfait. Vegeta est battu et j’ai régler les bugs. On peut passer aux choses sérieuses.



Burst

J’ai envie d’aller plus loin dans mon load testing. Ça tombe bien Vegeta a la haine maintenant. Je décide de multiplier par trois les chiffres. C’est 1500 requêtes que je vais envoyer toutes les secondes et pendant 5 secondes. Ca constitue un burst de charge important en très peu de temps. Aucun problème pour le faire avec la puissance de Vegeta. J’ai plus peur de comment mon API va réagir à cette attaque surpuissante. Allez, Final Flash !



vegeta attack -targets=targets.txt -header AppId:c7c734e9 -name=1500qps -rate=1500 -duration=5s > results.1500qps.bin;cat results.1500qps.bin | vegeta plot > plot.1500qps.html


burst


load testing


Tout de suite, tu vois que l’API prend cher aux burst. Malgré le système de queue et les requêtes optimisées, l’impact est significatif sur la première seconde. On monte à presque 1 seconde de temps de réponse aux burst initial. Ensuite, le cache prend le relais donc tout va bien. Je suis capable de tenir un énorme burst inattendu donc je suis rassuré. Maintenant qu’en est-il si je laisse Vegeta s’acharner mon API pendant une longue période ?



Taux constant d’attaque

Vegeta, dans la limite des capacités de ta machine, garantie un taux d’attaques par seconde sur autant de temps que tu veux. Testons comment réagit notre API à un stress test de 10 minutes. Je rajoute un petit rapport texte à la fin de la commande pour avoir un premier rapport dans la console. C’est parti pour 1500 requêtes seconde durant 10 minutes pour un total de 900 000 requêtes. C’est un Vegeta déchaîné et en colère qui s’abat sur mon API.



vegeta attack -targets=targets.txt -header AppId:c7c734e9 -name=1500qps -rate=1500 -duration=600s > results.1500qps.bin;cat results.1500qps.bin | vegeta plot > plot.1500qps.html;cat results.1500qps.bin | vegeta report -type=text


attack


Requests      [total, rate, throughput]  900000, 1500.00, 1500.00
Duration      [total, attack, wait]      10m0.000316382s, 9m59.999580104s, 736.278µs
Latencies     [mean, 50, 95, 99, max]    1.991021ms, 663.902µs, 4.565085ms, 11.903513ms, 1.032112359s
Bytes In      [total, mean]              895882509, 995.42
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    100.00%
Status Codes  [code:count]               200:900000


Load testing concluant ! C’est bon j’ai fini de traumatiser mon application. Je demande à Vegeta de se calmer et je le garde dans un coin pour la prochaine fois. Ship it !



Épilogue

Si tu veux des scénarios utilisateurs incroyables et de la configuration de l’espace : tourne-toi vers une solution comme Locust. Sinon Vegeta est vraiment une super alternative si tu veux tester les limites de ton application en cinq minutes. Sans compter le faite que t’as un Super Saiyan à porter de main dans ta machine maintenant.

Qui me parle ?

jesuisundev
Je suis un dev. En ce moment je suis Backend Développeur / DevOps à Ubisoft. Je suis passionné du dev et j'écris comme je parle. Je continue à te parler quotidiennement sur mon Twitter. Tu peux m'insulter à cette e-mail ou le faire directement dans les commentaires juste en dessous. Y'a même une newsletter !

Commentaire(s)

  1. Petite question, qu’as-tu utiliser pour ton système de queue ? La base de donnée c’est du MySQL derrière ? Et pour ton système de cache ? Merci !

  2. Pas mal comme outil, moi j’ai utilisé https://gatling.io/ par le passé. C’est pas en ligne de commande, du coup peut-être moins accessible pour les non devs, mais très paramétrable du coup, notamment en terme de scénario de montée en charge. Et pis ça fait des jolis graphs 😉

T'en penses quoi ?

Your email address will not be published. Required fields are marked *