emqtt-bench (le binaire s'appelle emqtt_bench) est un outil open source de benchmark MQTT édité par EMQ, écrit en Erlang, capable d'ouvrir des dizaines de milliers de connexions et de générer une charge de publication et d'abonnement depuis une seule machine. Il propose trois commandes — conn, sub et pub — et une longue liste d'options. Ce guide détaille chaque commande, les options qui comptent vraiment, l'usage de TLS et WebSocket, la mesure de latence et la lecture de ce qu'il affiche.
Pour la méthode générale — quoi mesurer et comment planifier un benchmark — voir test de charge d'un broker MQTT. Cette page est la référence de l'outil lui-même.
Installer ou lancer avec Docker
Le plus rapide est l'image Docker, dont l'entrypoint est emqtt_bench :
docker run --rm -it emqx/emqtt-bench pub --helpPour des exécutions longues ou très volumineuses, une installation native évite la surcharge réseau de Docker. Des paquets précompilés sont publiés sur la page des releases du projet sur GitHub. La compilation depuis les sources nécessite un Erlang/OTP récent et libatomic :
git clone https://github.com/emqx/emqtt-bench.git
cd emqtt-bench
make # BUILD_WITHOUT_QUIC=1 make si la compilation QUIC échoue
./emqtt_bench conn --helpAvant tout benchmark, vérifiez à la main l'hôte, le port et les identifiants avec un seul client dans le client MQTT en ligne. Si une connexion échoue, deux mille échoueront plus vite. Les exemples utilisent broker.connectmq.com, un endpoint partagé adapté aux vérifications rapides ; lancez les vrais benchmarks contre votre propre instance privée de broker en changeant -h et les identifiants.
Options communes à toutes les commandes
| Option | Signification | Défaut |
|---|---|---|
-h, --host | Hôte du broker ; une liste séparée par des virgules répartit les clients sur plusieurs hôtes | localhost |
-p, --port | Port du broker | 1883 |
-V, --version | Version du protocole MQTT : 3 (3.1), 4 (3.1.1) ou 5 | 5 |
-c, --count | Nombre de clients à démarrer | 200 |
-i, --interval | Millisecondes entre deux nouvelles connexions | 10 |
-R, --connrate | Connexions par seconde ; 0 revient à -i | 0 |
-u, -P | Identifiant et mot de passe | aucun |
-k, --keepalive | Keep alive en secondes | 300 |
-C, --clean | Clean session / clean start | true |
-x, --session-expiry | Session expiry interval MQTT 5 en secondes | 0 |
--prefix | Préfixe du client ID (aucun suffixe aléatoire s'il est défini) | <host>_bench_<cmd>_<random>_<n> |
--shortids | Client IDs courts : le numéro de séquence, ou préfixe + numéro | false |
-n, --startnumber | Premier numéro de séquence ; évite les collisions d'ID entre plusieurs instances | 0 |
--ifaddr | Adresse(s) IP locale(s) à utiliser, séparées par des virgules | celle du système |
--reconnect | Tentatives de reconnexion après une déconnexion | 0 (désactivé) |
--num-retry-connect | Nouvelles tentatives pour la connexion initiale | 0 |
-l, --lowmem | Mode mémoire réduite : moins de RAM par client, plus de CPU | désactivé |
Deux détails piègent souvent. D'abord, la version de protocole par défaut est MQTT 5 ; passez -V 4 pour tester un broker ou une configuration qui ne parle que 3.1.1. Ensuite, le keep alive par défaut de 300 s est bien plus long que celui de la plupart des appareils ; réglez -k sur la valeur de votre flotte si vous testez le comportement des connexions inactives.
Les client IDs doivent être uniques par broker. Si vous lancez plusieurs processus emqtt-bench contre le même broker, donnez à chacun son propre --prefix ou sa propre plage -n — des IDs en double provoquent des session takeovers qui ressemblent à des déconnexions aléatoires. Vous pouvez prévisualiser des formats d'ID avec le générateur de client ID.
conn : capacité de connexions
conn se contente de se connecter et de maintenir les connexions. Il répond à la question « combien de clients simultanés le broker supporte-t-il, et à quelle vitesse les accepte-t-il ? »
docker run --rm -it emqx/emqtt-bench conn \
-h broker.connectmq.com -p 1883 \
-c 5000 -R 500 -k 60 \
-u "$MQTT_USER" -P "$MQTT_PASS"Surveillez connect_succ grimper jusqu'à l'objectif et connect_fail rester à zéro. Une tempête de reconnexions — tous les appareils qui reviennent après une panne — se simule en augmentant -R. D'autres scénarios se trouvent dans le guide des tests de stress de connexion.
sub : subscribers
sub connecte des clients, abonne chacun à un topic, puis compte ce qu'il reçoit.
| Option | Signification | Défaut |
|---|---|---|
-t, --topic | Filtre de topic, avec placeholders (voir plus bas) | obligatoire |
-q, --qos | QoS de l'abonnement | 0 |
--payload-hdrs | Interprète les en-têtes ajoutés par le publisher (ts, cnt64) | aucun |
docker run --rm -it emqx/emqtt-bench sub \
-h broker.connectmq.com -p 1883 \
-c 100 -i 5 -q 1 \
-t 'testmqtt/bench/%i/data' \
-u "$MQTT_USER" -P "$MQTT_PASS"pub : publishers
pub connecte des clients et publie à intervalle fixe pour chaque client.
| Option | Signification | Défaut |
|---|---|---|
-t, --topic | Topic de publication, avec placeholders | obligatoire |
-I, --interval_of_msg | Millisecondes entre deux messages, par client | 1000 |
-s, --size | Taille du payload en octets | 256 |
-m, --message | Payload littéral, ou template://<file> | octets aléatoires |
-q, --qos | QoS de publication | 0 |
-r, --retain | Active le flag retain | false |
-L, --limit | S'arrête après ce nombre de messages ; 0 = illimité | 0 |
-F, --inflight | Nombre max. de messages QoS 1/2 non acquittés par client ; 0 = illimité | 1 |
-w, --wait-before-publishing | Ne publie qu'une fois que tous les publishers ont tenté de se connecter | false |
--payload-hdrs | Préfixe le payload avec ts (timestamp) et/ou cnt64 (compteur) | aucun |
docker run --rm -it emqx/emqtt-bench pub \
-h broker.connectmq.com -p 1883 \
-c 100 -I 100 -s 512 -q 1 -F 10 -w \
-t 'testmqtt/bench/%i/data' \
-u "$MQTT_USER" -P "$MQTT_PASS"Le débit visé vaut clients × (1000 / -I). Attention à -F : avec la fenêtre inflight par défaut de 1, chaque client QoS 1 attend chaque PUBACK avant d'envoyer le message suivant, si bien qu'avec une latence élevée un client n'atteint jamais son intervalle. Si pub_overrun augmente, le client n'a pas pu tenir son rythme ; augmentez -F ou baissez le débit. Les stratégies de test de throughput sont détaillées dans le guide des tests de throughput MQTT.
Placeholders de topic
Les placeholders dans -t permettent à une seule commande de créer de nombreux topics distincts :
| Placeholder | Remplacé par |
|---|---|
%i | Numéro de séquence du client (décalage -n inclus) |
%c | Client ID |
%u | L'identifiant passé avec -u |
%s | Numéro de séquence du message (pub uniquement) |
%rand_N | Entier aléatoire entre 1 et N |
Utiliser %i des deux côtés — pub -t 'testmqtt/bench/%i/data' et sub -t 'testmqtt/bench/%i/data' avec le même -c — associe le publisher N au subscriber N : routage un pour un. Un seul subscriber sur testmqtt/bench/+/data mesure au contraire le fan-in, et de nombreux subscribers sur un topic mesurent le fan-out. Vérifiez vos filtres avec le topic matcher.
TLS, WebSockets et QUIC
| Option | Signification |
|---|---|
-S, --ssl | Active TLS |
--ssl-version | Impose une version de TLS (implique --ssl) |
--cacertfile | Bundle CA pour vérifier le broker |
--certfile, --keyfile | Certificat et clé client (TLS mutuel) |
--ciphers | Restreint les cipher suites |
--ws | Utilise le transport WebSocket |
--quic | Utilise MQTT over QUIC (sur les brokers compatibles) |
# MQTT sur TLS
emqtt_bench conn -h broker.connectmq.com -p 8883 --ssl \
--cacertfile /etc/ssl/certs/ca-certificates.crt \
-c 1000 -R 100 -u "$MQTT_USER" -P "$MQTT_PASS"
# MQTT sur WebSocket sécurisé
emqtt_bench pub -h broker.connectmq.com -p 8084 --ws --ssl \
-c 50 -I 1000 -t 'testmqtt/bench/%i/ws' -u "$MQTT_USER" -P "$MQTT_PASS"emqtt-bench n'a pas d'option dédiée au chemin WebSocket ; le client emqtt sous-jacent utilise /mqtt, ce qui correspond à l'endpoint de ces exemples. Comparer la même exécution conn sur 1883 et 8883 montre directement le coût du handshake — voir tests de performance TLS MQTT.
Mesurer la latence
Lancez le subscriber et le publisher avec le même --payload-hdrs ts. Le publisher écrit un timestamp en millisecondes au début de chaque payload ; le subscriber le soustrait de sa propre horloge à la réception :
# terminal 1
emqtt_bench sub -h broker.connectmq.com -c 50 -q 1 \
-t 'testmqtt/bench/%i/lat' --payload-hdrs ts -u "$MQTT_USER" -P "$MQTT_PASS"
# terminal 2
emqtt_bench pub -h broker.connectmq.com -c 50 -I 200 -q 1 \
-t 'testmqtt/bench/%i/lat' --payload-hdrs ts -u "$MQTT_USER" -P "$MQTT_PASS"Le subscriber affiche alors une ligne publish_latency avg=…ms. C'est une moyenne ; pour des percentiles, activez --prometheus (qui expose un histogramme e2e_latency) ou utilisez le script du guide des tests de charge. Comme le timestamp provient de l'horloge du publisher, exécutez les deux sur la même machine ou gardez les horloges des machines synchronisées.
Lire la sortie
Chaque seconde, emqtt-bench affiche une ligne par compteur modifié, au format <temps> <compteur> total=<n> rate=<n>/sec :
10s connect_succ total=100 rate=0.00/sec
10s pub total=9871 rate=1000.12/sec
10s pub_succ total=9862 rate=999.40/sec| Compteur | Signification |
|---|---|
connect_succ / connect_fail | Connexions acceptées / échouées |
connect_retried, reconnect_succ | Nouvelles tentatives et reconnexions réussies |
connection_refused, connection_timeout, unreachable | Pourquoi les connexions ont échoué |
connection_idle | Connexions devenues inactives |
sub / sub_fail | Abonnements acceptés / refusés |
pub / pub_succ / pub_fail | Messages envoyés / acquittés / échoués |
pub_overrun | Un client n'a pas pu tenir son intervalle de publication |
pub_nosub | Le broker a signalé l'absence de subscribers correspondants (MQTT 5) |
recv | Messages reçus par les subscribers |
publish_latency | Latence moyenne de bout en bout (avec --payload-hdrs ts) |
Le schéma sain : les débits pub et recv correspondent à votre objectif et l'un à l'autre, pub_overrun reste à zéro et aucun compteur d'échec n'apparaît. Un connection_timeout ou connect_fail qui monte près d'un nombre rond (1 024, 65 535) signale généralement des limites sur le générateur de charge. Retrouvez les reason codes du broker avec l'outil des reason codes.
Faire monter en charge le générateur
- Descripteurs de fichiers. Augmentez
ulimit -nbien au-delà de-cavant de grosses exécutionsconn. - Ports. Une IP source n'ouvre qu'environ 64K connexions vers une adresse et un port du broker. Utilisez
--ifaddr 10.0.0.11,10.0.0.12ou plusieurs machines, et élargissez la plage de ports locaux avecsysctl. - Mémoire. Ajoutez
-lpour un très grand nombre de clients, au prix de plus de CPU. - CPU. Si le générateur dépasse environ 80 % de CPU, vos chiffres décrivent le générateur, pas le broker.
Voir le trafic du benchmark dans le client en ligne
emqtt-bench est le moyen le plus rapide d'appliquer une charge réaliste de connexions et de messages à un broker MQTT depuis la ligne de commande. Maîtrisez la poignée d'options qui façonnent la charge — -c, -R, -I, -q, -F et les placeholders de topic —, vérifiez que TLS et la version du protocole correspondent à la production, et lisez les compteurs comme des débits comparables d'une exécution à l'autre.
Questions fréquentes
Quelle différence entre -i et -R dans emqtt-bench ?
-i (--interval) est la pause en millisecondes entre deux nouvelles connexions, 10 par défaut. -R (--connrate) fixe à la place un débit de connexions par seconde ; quand il vaut 0 (par défaut), emqtt-bench revient à l'intervalle.
Comment mesurer la latence avec emqtt-bench ?
Lancez le subscriber et le publisher avec la même option --payload-hdrs ts. Le publisher préfixe chaque payload d'un timestamp en millisecondes et le subscriber affiche une ligne publish_latency avec la latence moyenne de bout en bout. Exécutez les deux sur une même machine ou gardez les horloges synchronisées.
Pourquoi emqtt-bench plafonne-t-il vers 64 000 connexions ?
Une adresse IP source ne peut ouvrir qu'environ 64K connexions TCP vers la même adresse et le même port du broker. Répartissez les clients sur plusieurs adresses locales avec --ifaddr ou sur plusieurs machines, et augmentez ulimit -n.



