Gatling peut tester la charge d'un broker MQTT grâce à son plugin MQTT : vous décrivez le comportement d'un appareil sous forme de scénario en Java, Kotlin ou Scala — connect, subscribe, publish, attente du message correspondant — et Gatling injecte des utilisateurs virtuels puis produit son rapport HTML avec percentiles de temps de réponse et throughput. C'est adapté aux équipes qui utilisent déjà Gatling pour HTTP et veulent le même workflow « simulation as code » pour MQTT.
Avant de commencer, connaissez la licence : le composant MQTT est distribué sous la Gatling Enterprise Component License. En local avec la Community Edition, il est limité à 5 utilisateurs virtuels et des tests de 5 minutes, ce qui suffit pour développer et valider une simulation. L'exécution à grande échelle nécessite Gatling Enterprise. Si cela ne vous convient pas, k6 avec xk6-mqtt, JMeter ou emqtt-bench sont des alternatives open source.
Configuration du projet
Le plus simple est de partir d'un des projets de démonstration Maven ou Gradle de Gatling. Ajoutez ensuite le plugin MQTT à côté des dépendances Gatling standard :
<dependency>
<groupId>io.gatling</groupId>
<artifactId>gatling-mqtt-java</artifactId>
<version>3.16.0</version>
<scope>test</scope>
</dependency>Utilisez la même version que vos autres artefacts Gatling. Les projets Scala utilisent gatling-mqtt au lieu de gatling-mqtt-java ; avec Gradle, la déclaration est gatlingImplementation("io.gatling:gatling-mqtt-java:3.16.0").
Le DSL MQTT n'est pas importé par défaut, chaque simulation a donc besoin de :
import io.gatling.javaapi.mqtt.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;Avant d'écrire la simulation, validez broker, port et identifiants avec un seul client dans le client MQTT en ligne. Vous saurez ainsi que tout échec ultérieur vient de la charge, pas de la configuration. N'utilisez l'endpoint partagé broker.connectmq.com que pour valider le scénario ; pour une vraie charge, pointez .broker(...) et les identifiants vers votre propre instance privée de broker.
Le protocole : broker, identifiants, QoS
Le protocol builder regroupe les réglages partagés par tous les utilisateurs virtuels :
MqttProtocolBuilder mqttProtocol = mqtt
.mqttVersion_5() // ou mqttVersion_3_1_1() (par défaut)
.broker("broker.connectmq.com", 1883) // TLS : port 8883 + .useTls(true)
.credentials(System.getenv("MQTT_USER"), System.getenv("MQTT_PASS"))
.keepAlive(30)
.qosAtLeastOnce() // QoS 0 par défaut
.cleanSession(true)
.reconnectAttemptsMax(3)
.correlateBy(jsonPath("$.id"));Deux réglages méritent attention :
- Client ID. Si vous ne définissez pas
clientId(...), Gatling en génère un aléatoire par utilisateur virtuel — le choix sûr pour un test de charge. Si vous le tirez d'un feeder, assurez-vous que les valeurs sont uniques, sinon les utilisateurs se voleront mutuellement leur session. correlateBy. Indique à Gatling comment associer un message entrant à la requête qui l'attend. Ici chaque payload contient un champid, ce qui permet de rattacher le message reçu au publish envoyé.
Un scénario de télémétrie d'appareil
Le scénario ci-dessous modélise un appareil : il se connecte, s'abonne à son propre topic, puis publie une mesure par seconde pendant une minute en attendant que chacune revienne via le broker.
package mqtt;
import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.mqtt.MqttDsl.*;
import io.gatling.javaapi.core.*;
import io.gatling.javaapi.mqtt.*;
import java.time.Duration;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;
public class MqttTelemetrySimulation extends Simulation {
MqttProtocolBuilder mqttProtocol = mqtt
.mqttVersion_5()
.broker("broker.connectmq.com", 1883)
.credentials(System.getenv("MQTT_USER"), System.getenv("MQTT_PASS"))
.keepAlive(30)
.qosAtLeastOnce()
.correlateBy(jsonPath("$.id"));
Iterator<Map<String, Object>> devices =
Stream.iterate(1, i -> i + 1)
.map(i -> Map.<String, Object>of("deviceId", "dev-" + i))
.iterator();
ScenarioBuilder telemetry = scenario("Device telemetry")
.feed(devices)
.exec(mqtt("Connect").connect())
.exec(mqtt("Subscribe").subscribe("testmqtt/gatling/#{deviceId}/data"))
.repeat(60, "n").on(
exec(
mqtt("Publish")
.publish("testmqtt/gatling/#{deviceId}/data")
.message(StringBody("{\"id\":\"#{deviceId}-#{n}\",\"temp\":21.5}"))
.await(Duration.ofSeconds(2))
.check(jsonPath("$.temp").exists())
).pause(Duration.ofSeconds(1))
);
{
int users = Integer.getInteger("users", 5);
setUp(
telemetry.injectOpen(rampUsers(users).during(Duration.ofSeconds(30)))
).protocols(mqttProtocol)
.assertions(
global().failedRequests().percent().lt(1.0),
details("Publish").responseTime().percentile3().lt(200)
);
}
}Le rôle de chaque élément :
- Feeder. Donne à chaque utilisateur virtuel un
deviceIdunique, utilisé dans le topic et dans l'id du message. repeat(60, "n"). Boucle 60 fois et expose le compteur sous#{n}, de sorte que chaque id de message est unique — indispensable pour la corrélation..await(Duration.ofSeconds(2)). Un check bloquant : l'utilisateur attend qu'un message portant l'id de corrélation arrive sur un topic abonné, ou échoue au bout de 2 secondes..expect(...)est la variante non bloquante ; combinez-la avecmqtt.waitForMessages()pour publier plusieurs messages avant d'attendre..check(jsonPath("$.temp").exists()). Valide le contenu du message rattaché, pas seulement son arrivée.- Assertions. Font échouer l'exécution si plus de 1 % des requêtes échouent ou si le 95e percentile de
Publishdépasse 200 ms (percentile3()correspond au 95e par défaut). Ajustez les deux selon votre propre référence.
Les topics suivent testmqtt/gatling/<device>/data ; si vous ajoutez plus tard des abonnements avec wildcards, vérifiez les motifs dans le topic matcher.
Choisir un profil d'injection
Dans une simulation MQTT, chaque utilisateur virtuel est un appareil qui garde une connexion pendant tout le scénario : le profil d'injection détermine donc combien de connexions existent en même temps et à quel rythme elles arrivent.
| Profil | Pour tester | Exemple |
|---|---|---|
atOnceUsers(n) | Une tempête de reconnexions : tous les appareils se connectent au même instant | atOnceUsers(5) |
rampUsers(n).during(d) | Une flotte stable qui se connecte progressivement ; le point de départ habituel | rampUsers(5).during(Duration.ofSeconds(30)) |
constantUsersPerSec(r).during(d) | L'arrivée continue de nouveaux appareils (sessions qui commencent et finissent) | constantUsersPerSec(1).during(Duration.ofMinutes(2)) |
rampUsersPerSec(a).to(b).during(d) | Un débit d'arrivée croissant, pour trouver le point où les connexions ralentissent | rampUsersPerSec(1).to(5).during(Duration.ofMinutes(1)) |
Le nombre de connexions simultanées vaut à peu près débit d'arrivée × durée du scénario. Avec 60 publications espacées d'une seconde par utilisateur, chacun reste connecté environ une minute : constantUsersPerSec(10) se stabilise donc autour de 600 appareils simultanés. Gardez ce calcul en tête pour dimensionner une exécution, et rappelez-vous qu'avec la Community Edition le total reste plafonné à 5 utilisateurs.
Vous pouvez aussi combiner plusieurs scénarios dans un même setUp, par exemple une rampe d'appareils de télémétrie et un petit groupe d'utilisateurs de tableau de bord abonnés à un wildcard. Chaque scénario conserve ses propres noms de requête, et le rapport affiche les deux charges séparément.
Lancer la simulation
export MQTT_USER=username MQTT_PASS=password
./mvnw gatling:test \
-Dgatling.simulationClass=mqtt.MqttTelemetrySimulation \
-Dusers=5Avec la Community Edition, gardez users à 5 maximum et une durée inférieure à 5 minutes — l'exécution s'arrête à ces limites. C'est suffisant pour prouver que le scénario, la corrélation et les checks fonctionnent. Envoyez le même projet sur Gatling Enterprise pour l'exécuter avec des milliers d'utilisateurs et plusieurs générateurs de charge.
Lire le rapport HTML
À la fin, Gatling affiche le chemin vers target/gatling/<simulation>-<timestamp>/index.html. Le rapport regroupe tout par nom de requête : les noms passés à mqtt("…") sont vos titres.
| Requête | Le temps de réponse correspond à | À surveiller |
|---|---|---|
| Connect | Jusqu'à l'acceptation de la connexion par le broker (CONNACK), TLS compris | Échecs ou connexions lentes pendant la montée en charge |
| Subscribe | Jusqu'à la confirmation de l'abonnement (SUBACK) | Rarement un goulet ; les échecs signalent souvent un problème d'ACL |
Publish (avec await) | Du publish jusqu'à l'arrivée du message corrélé | Percentiles de latence de bout en bout et timeouts |
Graphiques utiles :
- Percentiles du temps de réponse dans le temps. Un p95 ou p99 qui monte pendant la montée en charge montre où le broker ou le réseau commence à saturer.
- Requêtes par seconde. Comparez-les au débit prévu (ici utilisateurs × 1 msg/s). Si elles plafonnent sous l'objectif, quelque chose bride le trafic.
- Tableau des erreurs. Des timeouts sur
awaitsignifient que les messages ne sont pas revenus à temps — vérifiez le QoS, les limites de files et pourquoi des messages se perdent. Des erreurs de connexion à un nombre rond d'utilisateurs indiquent souvent une limite ; décodez les reason codes du broker avec l'outil des reason codes MQTT.
Une méthode plus large pour distinguer les limites du broker de celles du générateur de charge se trouve dans interpréter les résultats de benchmark MQTT.
Conseils pour des simulations réalistes
- Modélisez des sessions, pas des requêtes. Les vrais appareils restent connectés ; gardez la connexion ouverte pendant la boucle au lieu de vous reconnecter à chaque message.
- Reprenez vos tailles de payload. Remplacez le petit JSON par des payloads semblables aux vôtres ; vérifiez leur taille réelle avec le calculateur de taille de paquet.
- Séparez fan-out et un pour un. Un scénario de tableau de bord abonné à
testmqtt/gatling/+/datareçoit les messages de tous les appareils ; exécutez-le comme scénario distinct pour que sa charge reste visible. - Surveillez le générateur de charge. Une JVM saturée gonfle les temps de réponse. Contrôlez le CPU et le GC de la machine qui exécute Gatling.
- Versionnez la simulation. Relancez-la après chaque mise à jour ou changement de configuration du broker pour détecter les régressions.
Voir le trafic Gatling dans le client en ligne
Le plugin MQTT de Gatling vous offre des scénarios lisibles et versionnés, avec une corrélation et des checks que la plupart des outils MQTT n'ont pas. Construisez et validez la simulation dans les limites de la Community Edition, exécutez-la à grande échelle là où votre licence le permet, et lisez toujours les temps de publish avec des checks await : c'est la latence que ressentent vos appareils.
Questions fréquentes
Le support MQTT de Gatling est-il gratuit ?
Le plugin MQTT (gatling-mqtt-java) est publié sur Maven Central sous la Gatling Enterprise Component License. Avec la Community Edition, il est limité à 5 utilisateurs virtuels et à des tests de 5 minutes ; ces limites sont levées quand la simulation tourne sur Gatling Enterprise.
Gatling prend-il en charge MQTT 5 ?
Oui, le protocol builder propose mqttVersion_3_1(), mqttVersion_3_1_1() (par défaut) et mqttVersion_5(). Gatling précise que toutes les fonctionnalités de MQTT 5 ne sont peut-être pas encore disponibles : vérifiez la documentation si vous dépendez de l'une d'elles.
Comment Gatling mesure-t-il le temps de réponse MQTT ?
Connect et subscribe sont mesurés jusqu'à la réponse du broker. Pour publish, ajoutez un check await ou expect : Gatling enregistre alors le temps jusqu'à l'arrivée d'un message correspondant, ce qui donne la latence de bout en bout dans le rapport.



