Comment mesurer le débit et la limite de concurrence via un proxy avec k6 et JMeter
Sommaire de l'article
- Introduction : pourquoi connaître la limite à l'avance, plutôt qu'au moment d'un gros envoi de données
- Préparation préalable : outils, exigences et accès
- Concepts de base en termes simples
- Étape 1 : préparer la cible de test et les données du proxy
- Étape 2 : comprendre la méthodologie de charge correcte
- Étape 3 : k6 - scénario prêt à l'emploi avec proxy et charge par paliers
- Étape 4 : jmeter - le même scénario avec configuration du proxy dans le plan de test
- Étape 5 : distinguer la limite du proxy de celle du client et de la limite du serveur - trois vérifications
- Étape 6 : que faire avec le résultat - threads, pool et temps d'envoi
- Étape 7 : éthique de la charge et modes doux
- Vérification du résultat : liste de contrôle de préparation
- Erreurs typiques et solutions
- Possibilités supplémentaires et optimisation
- Faq : questions fréquentes sur la mesure du débit via un proxy
- Conclusion
Travailler via un proxy soulève presque toujours une question : combien de requêtes parallèles la chaîne "votre client - proxy - serveur cible" peut-elle réellement supporter avant que les latences ne grimpent et que les erreurs commencent à pleuvoir ? Ce guide vous apprendra à mesurer tout cela à l'avance, et non au moment d'un gros envoi de données, quand chaque heure de panne compte.
Introduction : pourquoi connaître la limite à l'avance, plutôt qu'au moment d'un gros envoi de données
Imaginez une situation typique. Vous lancez une grosse tâche de collecte de données publiques via un pool de proxys. Tout se passe bien sur les premiers milliers de requêtes, puis les latences augmentent, certaines requêtes commencent à échouer par timeout, et vous ne comprenez pas : est-ce votre code, le proxy ou le serveur cible qui est en cause ? À ce stade, vous avez déjà perdu du temps et, peut-être, des données.
Il est bien plus judicieux de mener à l'avance un test de charge contrôlé et de trouver le point de dégradation. Ainsi, vous pourrez choisir un nombre de threads sûr et planifier correctement le temps de l'envoi de données.
Ce que le lecteur obtiendra au final
Après avoir suivi ce guide, vous serez en mesure de :
- Créer un scénario de charge correct dans k6 et l'exécuter via un proxy.
- Reproduire le même scénario dans JMeter avec la configuration du proxy dans le plan de test.
- Lire le rapport : comprendre le RPS (requêtes par seconde), les latences par percentiles et le taux d'erreurs.
- Distinguer la limite du proxy de celle de votre client et de celle du serveur cible.
- Convertir les résultats en nombre de threads, taille de pool et temps d'envoi estimé.
À qui s'adresse ce guide
Ce contenu s'adresse aux ingénieurs, analystes de données et développeurs de niveau intermédiaire. Si vous avez déjà écrit de simples scripts en JavaScript ou lancé des programmes en ligne de commande, vous serez à l'aise. Pour les débutants, nous expliquons chaque terme simplement.
Ce qu'il faut savoir à l'avance
Des compétences de base suffisent : ouvrir un terminal, installer un programme et éditer un fichier texte. La connaissance du HTTP au niveau "ce qu'est une requête et une réponse" est un plus, mais pas indispensable.
Temps nécessaire
L'installation des outils prendra environ 30 à 40 minutes. Vous lancerez votre premier test fonctionnel avec k6 en une heure. Le cycle complet avec JMeter et l'analyse prendra 3 à 4 heures de travail calme.
⚠️ Attention : Tous les exemples de ce guide sont destinés à tester votre propre environnement ou des ressources pour lesquelles vous avez une autorisation explicite de charger. Tester des services tiers sans leur consentement est inacceptable. Nous aborderons l'éthique à la fin.
Préparation préalable : outils, exigences et accès
Avant de mesurer, il faut préparer l'environnement de travail. Nous listons ici tout le nécessaire et montrons comment installer chaque composant.
Outils et accès nécessaires
- k6 - outil léger de test de charge, les scénarios s'écrivent en JavaScript.
- Apache JMeter - outil classique avec interface graphique en Java.
- Java 17 ou plus récent - requis pour JMeter.
- Accès à un proxy Proxeon : adresse, port, identifiant et mot de passe. Ces données sont disponibles dans votre espace client du service.
- Cible de test - votre propre environnement ou une ressource autorisée.
Exigences système
Une machine avec 4 cœurs de processeur et 8 Go de RAM est suffisante pour un travail confortable. Pour une charge élevée (des milliers d'utilisateurs virtuels), 8 cœurs et 16 Go sont recommandés. Système d'exploitation - Windows, macOS ou Linux ; tous les outils sont multiplateformes.
Conseil : Lancez le générateur de charge sur une machine distincte ou un serveur cloud séparé. Ainsi, vous ne confondrez pas la charge sur votre ordinateur portable avec celle sur le proxy.
Installation de k6
- Utilisez la méthode d'installation officielle pour votre système : sur macOS via le gestionnaire de paquets Homebrew avec la commande brew install k6.
- Sur Windows, utilisez le gestionnaire de paquets Chocolatey : choco install k6.
- Sur Linux, téléchargez le paquet depuis le dépôt du projet et installez-le via le gestionnaire de paquets système.
- Vérifiez l'installation avec la commande k6 version - vous verrez le numéro de version en réponse.
✅ Vérification : Si la commande k6 version affiche une ligne avec la version sans erreur "commande introuvable", l'outil est correctement installé.
Installation de Java et JMeter
- Installez OpenJDK version 17 ou plus récente et vérifiez avec la commande java -version.
- Téléchargez l'archive Apache JMeter depuis le site officiel du projet, section téléchargements.
- Extrayez l'archive dans un dossier pratique, par exemple votre répertoire personnel.
- Accédez au sous-dossier bin dans le JMeter extrait.
- Exécutez le fichier jmeter (sur Linux et macOS) ou jmeter.bat (sur Windows).
- Attendez l'apparition de la fenêtre graphique avec l'arborescence du plan de test à gauche.
✅ Vérification : Si la fenêtre JMeter s'ouvre avec l'élément "Test Plan" dans l'arborescence à gauche, tout est prêt.
Sauvegardes et préparation de l'environnement
Si vous testez votre propre service, faites un snapshot ou une sauvegarde des données de l'environnement à l'avance. La charge ne doit pas endommager la production. Si possible, utilisez une copie de l'environnement plutôt que le serveur de production.
Concepts de base en termes simples
Pour lire les rapports sans vous perdre dans les termes, examinons les concepts clés.
Débit et RPS
Le débit représente la quantité de travail utile qu'un système accomplit par unité de temps. Dans le contexte HTTP, on le mesure généralement en RPS - requêtes par seconde. Plus le RPS est élevé avec des latences acceptables, mieux c'est.
Latence et percentiles
La latence est le temps écoulé entre l'envoi d'une requête et la réception de la réponse. Une seule valeur moyenne est trompeuse, car les rares requêtes lentes s'y dissolvent. C'est pourquoi on utilise des percentiles.
Le percentile p95 signifie : 95 % des requêtes ont été plus rapides que cette valeur, et 5 % plus lentes. Le percentile p99 montre le comportement des requêtes les plus lentes. Ce sont p95 et p99 qui reflètent le mieux l'expérience réelle sous charge.
Taux d'erreurs et point de dégradation
Le taux d'erreurs est le pourcentage de requêtes qui échouent : timeouts, refus de connexion, codes de réponse 5xx. Le point de dégradation est le moment où l'augmentation de la charge cesse d'augmenter le RPS, mais où les latences et les erreurs grimpent fortement. C'est la limite recherchée.
Concurrence et utilisateurs virtuels
La concurrence représente le nombre de requêtes exécutées simultanément. Dans k6, elle est définie via VU (utilisateurs virtuels) ; dans JMeter, via le nombre de threads dans le groupe de threads. Un VU ou un thread envoie des requêtes séquentiellement, et un grand nombre d'entre eux créent une charge parallèle.
Le proxy dans la chaîne de charge
Le proxy est un nœud intermédiaire par lequel passent vos requêtes. Il a sa propre limite de connexions simultanées et de bande passante. Notre objectif est de comprendre à quel niveau de concurrence ce nœud devient le goulet d'étranglement.
Conseil : Gardez à l'esprit la loi de Little : le nombre moyen de requêtes simultanées est approximativement égal au RPS multiplié par la latence moyenne en secondes. Cela aide à estimer rapidement la concurrence nécessaire.
Étape 1 : Préparer la cible de test et les données du proxy
Objectif de l'étape : obtenir une adresse fonctionnelle de la cible et une chaîne de connexion au proxy correctement formatée.
- Déterminez l'URL de la cible que vous allez charger. Prenons votre environnement, par exemple une adresse du type https://stend.local/api/health.
- Vérifiez que la cible répond rapidement et de manière stable à une requête unique via un navigateur classique ou l'utilitaire curl.
- Récupérez les données du proxy Proxeon depuis votre espace client : hôte, port, nom d'utilisateur et mot de passe.
- Construisez la chaîne de connexion au format http://NOM:MOT_DE_PASSE@HOTE:PORT. Par exemple : http://user:pass@proxy.proxeon.net:8000.
- Testez le proxy avec une requête unique curl, en remplaçant l'exemple par vos données.
Exemple de requête de vérification :
curl -x http://user:pass@proxy.proxeon.net:8000 -H "Accept: application/json" https://stend.local/api/health⚠️ Attention : Ne stockez jamais l'identifiant et le mot de passe du proxy directement dans le code qui pourrait finir dans un dépôt. Utilisez des variables d'environnement. Nous le montrerons aux étapes suivantes.
Résultat attendu : curl via le proxy renvoie une réponse correcte de votre cible, sans erreur de connexion.
Problèmes possibles : si curl se bloque, vérifiez le port et le pare-feu. Si une erreur d'authentification 407 apparaît, revérifiez l'identifiant et le mot de passe.
✅ Vérification : Vous voyez le corps de la réponse de la cible, obtenu via le proxy. La chaîne fonctionne donc.
Étape 2 : Comprendre la méthodologie de charge correcte
Objectif de l'étape : assimiler pourquoi une salve unique est inutile et comment construire un profil de charge correct.
Pourquoi une salve unique est trompeuse
Si vous lancez d'un seul coup mille requêtes, vous obtiendrez un beau chiffre, mais insignifiant. Une telle salve ne montre pas le comportement stable. Le système peut avaler le pic grâce aux tampons, puis se dégrader. Ou, à l'inverse, s'étouffer au démarrage à cause de connexions froides.
Les trois phases d'un test correct
Un test de charge correct se compose de trois phases :
- Échauffement (warm-up). Pendant les 30 à 60 premières secondes, on monte la charge progressivement. Les pools de connexions, les caches DNS et les structures internes se réchauffent. Les données de l'échauffement ne sont pas incluses dans les statistiques finales.
- Montée par paliers (ramp-up steps). On augmente la concurrence par paliers : par exemple 10, 25, 50, 100, 200 VU, en maintenant chaque palier pendant 1 à 2 minutes. Ainsi, on voit à quel palier la dégradation commence.
- Palier stable (steady state). On fixe la charge à un niveau légèrement inférieur à la limite et on la maintient pendant 5 à 10 minutes. Ce palier montre si le système est stable sous charge constante, sans fuites ni accumulation de files d'attente.
Conseil : Ne tirez jamais de conclusions sur les 30 premières secondes du test. Laissez le système atteindre un régime stable, puis regardez les chiffres.
Ce que l'on enregistre à chaque palier
- Le RPS atteint.
- Les latences p50, p95, p99.
- Le taux d'erreurs.
- Le nombre de VU ou de threads actifs.
Le point de dégradation se détermine ainsi : on trouve le palier après lequel le RPS a cessé d'augmenter, tandis que p95 et le taux d'erreurs ont commencé à grimper fortement. Le palier précédent est votre point de travail sûr.
✅ Vérification : Vous pouvez expliquer en vos propres mots en quoi l'échauffement diffère du palier stable et pourquoi la montée par paliers est nécessaire.
Étape 3 : k6 - scénario prêt à l'emploi avec proxy et charge par paliers
Objectif de l'étape : créer et exécuter un scénario k6 fonctionnel qui traverse l'échauffement, les paliers et le palier stable via un proxy.
Comment k6 fonctionne avec un proxy
k6 lit l'adresse du proxy dans les variables d'environnement HTTP_PROXY et HTTPS_PROXY. C'est pratique : vous n'avez pas besoin de coder en dur les données dans le script, il suffit de les transmettre au lancement.
Script prêt à l'emploi load-test.js
Créez un fichier load-test.js et collez-y le code suivant. Remplacez l'adresse de la cible par la vôtre.
import http from 'k6/http'; import { check, sleep } from 'k6'; import { Trend, Rate, Counter } from 'k6/metrics'; const latency = new Trend('req_latency', true); const errors = new Rate('req_errors'); const ok = new Counter('req_ok'); export const options = { discardResponseBodies: true, thresholds: { req_errors: ['rate<0.02'], http_req_duration: ['p(95)<1500', 'p(99)<3000'], }, scenarios: { ramp: { executor: 'ramping-vus', startVUs: 0, stages: [ { duration: '1m', target: 10 }, { duration: '2m', target: 25 }, { duration: '2m', target: 50 }, { duration: '2m', target: 100 }, { duration: '2m', target: 200 }, { duration: '5m', target: 200 }, { duration: '1m', target: 0 }, ], gracefulRampDown: '30s', }, }, }; const TARGET = __ENV.TARGET_URL || 'https://stend.local/api/health'; export default function () { const res = http.get(TARGET, { timeout: '10s', tags: { name: 'target' } }); latency.add(res.timings.duration); const good = check(res, { 'status is 200': (r) => r.status === 200 }); errors.add(!good); if (good) ok.add(1); sleep(0.5); }Comment exécuter le scénario via un proxy
- Ouvrez un terminal dans le dossier contenant le script.
- Définissez les variables d'environnement avec l'adresse du proxy et la cible. Sur Linux et macOS, exécutez l'exportation des variables.
- Lancez k6 avec la commande d'exécution du script.
Exemple d'exécution sur Linux et macOS :
export HTTP_PROXY=http://user:pass@proxy.proxeon.net:8000 export HTTPS_PROXY=http://user:pass@proxy.proxeon.net:8000 export TARGET_URL=https://stend.local/api/health k6 run load-test.jsSur Windows dans PowerShell, les variables se définissent avec la syntaxe $env :
$env:HTTP_PROXY="http://user:pass@proxy.proxeon.net:8000"; $env:HTTPS_PROXY="http://user:pass@proxy.proxeon.net:8000"; $env:TARGET_URL="https://stend.local/api/health"; k6 run load-test.jsConseil : Le paramètre discardResponseBodies désactive le stockage des corps de réponse en mémoire. Cela réduit la charge sur le générateur lui-même et évite de confondre sa surcharge avec la limite du proxy.
Lecture du rapport k6
Après la fin du test, k6 affiche un résumé. Portez attention aux lignes clés :
- http_reqs - nombre total de requêtes et RPS moyen entre parenthèses. C'est votre débit.
- http_req_duration - latences, avec avg, min, med, max et percentiles p(90), p(95).
- req_errors et http_req_failed - taux d'erreurs.
- vus - nombre d'utilisateurs virtuels à un moment donné.
La ligne thresholds montrera si vos seuils ont été respectés. Si une croix apparaît à côté, le seuil a été violé - cela signifie que sur cette configuration, la limite est déjà atteinte ou dépassée.
⚠️ Attention : Les valeurs target dans stages doivent être adaptées à votre système. La valeur 200 VU est un exemple. Si votre cible ou la limite de votre forfait proxy est inférieure, commencez avec des paliers plus modestes, par exemple jusqu'à 50.
Résultat attendu : le test est terminé, vous voyez un résumé avec le RPS, les percentiles et le taux d'erreurs.
Problèmes possibles : si toutes les requêtes échouent, vérifiez les variables du proxy. Si le générateur consomme 100 % du CPU - réduisez le nombre de VU ou lancez le test sur une machine plus puissante.
✅ Vérification : Dans le résumé k6, http_reqs est non nul et le taux d'erreurs est inférieur à votre seuil, du moins sur les premiers paliers.
Étape 4 : JMeter - le même scénario avec configuration du proxy dans le plan de test
Objectif de l'étape : créer un plan équivalent dans JMeter avec proxy, paliers et collecte de métriques.
Créer un groupe de threads
- Dans JMeter ouvert, cliquez avec le bouton droit sur l'élément Test Plan.
- Sélectionnez Add - Threads (Users) - Thread Group.
- Dans le champ Number of Threads, définissez le nombre maximal de threads, par exemple 200.
- Dans le champ Ramp-up period, indiquez la durée de montée en charge en secondes, par exemple 540, pour reproduire la montée par paliers de k6.
- Dans le champ Loop Count, cochez Infinite, et nous définirons la durée avec un minuteur et le planificateur.
Configuration du proxy dans HTTP Request Defaults
Pour ne pas spécifier le proxy dans chaque requête, définissons-le une seule fois.
- Cliquez avec le bouton droit sur Thread Group et sélectionnez Add - Config Element - HTTP Request Defaults.
- Dans l'élément ouvert, trouvez l'onglet des paramètres du serveur proxy.
- Dans le champ Server Name or IP (bloc Proxy), saisissez l'hôte du proxy, par exemple proxy.proxeon.net.
- Dans le champ Port Number (Proxy), saisissez le port, par exemple 8000.
- Dans les champs Username et Password (Proxy), saisissez votre identifiant et votre mot de passe.
Ajouter la requête HTTP elle-même
- Cliquez avec le bouton droit sur Thread Group, sélectionnez Add - Sampler - HTTP Request.
- Dans le champ Protocol, saisissez https.
- Dans le champ Server Name or IP, saisissez le domaine de la cible, par exemple stend.local.
- Dans le champ Path, saisissez le chemin, par exemple /api/health.
- Dans le champ Method, laissez GET.
Ajouter un délai entre les requêtes
- Cliquez avec le bouton droit sur HTTP Request et sélectionnez Add - Timer - Constant Timer.
- Dans le champ Thread Delay, saisissez 500 millisecondes, pour reproduire le sleep de k6.
Configurer la collecte de métriques
- Cliquez avec le bouton droit sur Thread Group et ajoutez Add - Listener - Summary Report.
- Ajoutez également Add - Listener - Aggregate Report - il affiche les percentiles.
- Pour les tests longs, n'utilisez pas de listeners graphiques, ils consomment de la mémoire. À la place, enregistrez les résultats dans un fichier.
Conseil : Pour les tests lourds, lancez JMeter en mode non graphique depuis le terminal. Ainsi, le générateur consacre ses ressources à la charge, pas au rendu des graphiques.
Exemple d'exécution en mode non graphique :
jmeter -n -t plan.jmx -l results.jtl -e -o reportIci, -n lance sans interface graphique, -t indique le fichier du plan, -l le fichier de résultats bruts, et -e -o crée un rapport HTML dans le dossier report.
Lecture du rapport JMeter
Ouvrez index.html dans le dossier report. Indicateurs clés :
- Throughput - débit en requêtes par seconde.
- Response Times Percentiles - graphique des percentiles de latence.
- Error percentage - taux d'erreurs.
- Active Threads Over Time - évolution de la concurrence.
⚠️ Attention : Pour l'authentification du proxy, JMeter peut parfois nécessiter une configuration supplémentaire de l'autorisation Basic. Si vous voyez des erreurs massives 407, ajoutez un élément HTTP Authorization Manager avec les données du proxy.
Résultat attendu : le rapport HTML de JMeter s'ouvre et affiche le throughput, les percentiles et le taux d'erreurs.
✅ Vérification : Les valeurs de throughput et de percentiles dans JMeter sont comparables aux résultats de k6 avec les mêmes paliers. De légères différences sont normales.
Étape 5 : Distinguer la limite du proxy de celle du client et de la limite du serveur - trois vérifications
Objectif de l'étape : déterminer précisément lequel des trois nœuds est devenu le goulet d'étranglement.
Quand vous observez une dégradation, il est essentiel de comprendre sa source. Effectuez trois vérifications de contrôle.
Vérification 1 : votre client n'est-il pas le goulot ?
- Pendant le test, ouvrez le moniteur système sur la machine génératrice.
- Surveillez l'utilisation du CPU et de la RAM du processus k6 ou JMeter.
- Vérifiez la limite des descripteurs de fichiers sur Linux avec la commande ulimit -n.
Si le CPU du générateur est proche de 100 % ou si vous atteignez la limite de descripteurs, c'est le client qui est en cause, pas le proxy. Augmentez la limite de descripteurs, réduisez le nombre de VU ou utilisez une machine plus puissante.
Conseil : Un signe de surcharge du client est l'augmentation des latences en même temps que l'augmentation de l'utilisation du CPU du générateur, avec un RPS inchangé. Le proxy n'y est pour rien.
Vérification 2 : le serveur cible n'est-il pas le goulot ?
- Lancez un court test directement, sans proxy, en supprimant les variables HTTP_PROXY et HTTPS_PROXY.
- Comparez le RPS et les percentiles avec les résultats via le proxy.
Si, à la fois directement et via le proxy, la limite de RPS est presque identique, le goulot se trouve sur le serveur cible. Le proxy n'ajoute qu'un léger délai fixe.
⚠️ Attention : Le test direct ne doit être effectué que sur votre propre environnement. Ne chargez pas de ressources tierces sans autorisation, même à des fins de diagnostic.
Vérification 3 : isoler le proxy lui-même
- Mettez en place une maquette légère sur votre environnement qui répond instantanément avec un code 200 OK et un corps vide.
- Exécutez le test via le proxy contre cette maquette.
La maquette répond presque instantanément, donc les latences et la limite de RPS sont désormais principalement déterminées par le proxy et le réseau. Si le RPS plafonne précisément sur la maquette, vous avez trouvé la limite du proxy.
Résumons la logique avec un simple tableau de décision en mots :
- CPU du générateur élevé, RPS ne monte pas - limite du client.
- Directement et via le proxy identique - limite du serveur cible.
- Sur une maquette rapide via le proxy, le RPS plafonne - limite du proxy.
Résultat attendu : vous identifiez le nœud spécifique qui limite votre chaîne.
✅ Vérification : Vous avez effectué les trois vérifications et pouvez justifier où se trouve le goulot d'étranglement.
Étape 6 : Que faire avec le résultat - threads, pool et temps d'envoi
Objectif de l'étape : transformer les chiffres du test en réglages pratiques pour votre tâche de travail.
Choix d'un nombre sûr de threads
Prenez le palier avant le point de dégradation. Supposons qu'avec 100 VU vous obteniez un RPS stable de 180, p95 autour de 900 ms et des erreurs sous 1 %, tandis qu'à 200 VU le RPS n'augmente pas mais p95 bondit à 4 secondes. Alors le point de travail est autour de 100 VU, et pour une marge de sécurité, prenez 80-90.
Calcul de la taille du pool de proxys
Si un nœud proxy supporte de manière stable N connexions parallèles, et que vous avez besoin de M connexions simultanées, la taille minimale du pool est M divisé par N, arrondi au supérieur, plus une marge. Une marge de 20 à 30 % couvre les moments où une partie des connexions est occupée par des réponses lentes.
Conseil : Prévoyez toujours une marge de pool. Les réponses réelles sont plus lentes que la maquette, donc les connexions sont retenues plus longtemps et la concurrence réelle est plus élevée que prévu.
Estimation du temps d'envoi
La formule est simple : le temps en secondes est égal au nombre total de requêtes divisé par le RPS stable. Si vous devez collecter 1 000 000 requêtes avec un RPS stable de 180, cela représente environ 5556 secondes, soit environ 1 heure 33 minutes sans compter les pauses et les réessais.
- Prenez le RPS stable du palier de travail.
- Divisez le volume total de la tâche par ce RPS.
- Ajoutez 15 à 20 % pour les réessais de requêtes échouées et les pauses.
Exemple de calcul en pseudo-code pour plus de clarté :
total = 1000000; rps = 180; base_sec = total / rps; final_sec = base_sec * 1.2;