Tests de brokers

Guide emqtt-bench : toutes les commandes et options expliquées

Guide complet d'emqtt-bench : modes conn, pub et sub, options importantes, TLS et WebSocket, en-têtes de latence et lecture des compteurs affichés en sortie.

Mis à jour · 10 min de lecture

Guide emqtt-bench : toutes les commandes et options expliquées

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 :

Lancer avec Docker
docker run --rm -it emqx/emqtt-bench pub --help

Pour 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 :

Compiler depuis les sources
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 --help

Avant 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

OptionSignificationDéfaut
-h, --hostHôte du broker ; une liste séparée par des virgules répartit les clients sur plusieurs hôteslocalhost
-p, --portPort du broker1883
-V, --versionVersion du protocole MQTT : 3 (3.1), 4 (3.1.1) ou 55
-c, --countNombre de clients à démarrer200
-i, --intervalMillisecondes entre deux nouvelles connexions10
-R, --connrateConnexions par seconde ; 0 revient à -i0
-u, -PIdentifiant et mot de passeaucun
-k, --keepaliveKeep alive en secondes300
-C, --cleanClean session / clean starttrue
-x, --session-expirySession expiry interval MQTT 5 en secondes0
--prefixPréfixe du client ID (aucun suffixe aléatoire s'il est défini)<host>_bench_<cmd>_<random>_<n>
--shortidsClient IDs courts : le numéro de séquence, ou préfixe + numérofalse
-n, --startnumberPremier numéro de séquence ; évite les collisions d'ID entre plusieurs instances0
--ifaddrAdresse(s) IP locale(s) à utiliser, séparées par des virgulescelle du système
--reconnectTentatives de reconnexion après une déconnexion0 (désactivé)
--num-retry-connectNouvelles tentatives pour la connexion initiale0
-l, --lowmemMode mémoire réduite : moins de RAM par client, plus de CPUdé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 ? »

5 000 clients à 500 connexions par seconde
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.

OptionSignificationDéfaut
-t, --topicFiltre de topic, avec placeholders (voir plus bas)obligatoire
-q, --qosQoS de l'abonnement0
--payload-hdrsInterprète les en-têtes ajoutés par le publisher (ts, cnt64)aucun
100 subscribers, un topic chacun
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.

OptionSignificationDéfaut
-t, --topicTopic de publication, avec placeholdersobligatoire
-I, --interval_of_msgMillisecondes entre deux messages, par client1000
-s, --sizeTaille du payload en octets256
-m, --messagePayload littéral, ou template://<file>octets aléatoires
-q, --qosQoS de publication0
-r, --retainActive le flag retainfalse
-L, --limitS'arrête après ce nombre de messages ; 0 = illimité0
-F, --inflightNombre max. de messages QoS 1/2 non acquittés par client ; 0 = illimité1
-w, --wait-before-publishingNe publie qu'une fois que tous les publishers ont tenté de se connecterfalse
--payload-hdrsPréfixe le payload avec ts (timestamp) et/ou cnt64 (compteur)aucun
100 publishers, 10 msg/s chacun = 1 000 msg/s
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 :

PlaceholderRemplacé par
%iNuméro de séquence du client (décalage -n inclus)
%cClient ID
%uL'identifiant passé avec -u
%sNuméro de séquence du message (pub uniquement)
%rand_NEntier 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

OptionSignification
-S, --sslActive TLS
--ssl-versionImpose une version de TLS (implique --ssl)
--cacertfileBundle CA pour vérifier le broker
--certfile, --keyfileCertificat et clé client (TLS mutuel)
--ciphersRestreint les cipher suites
--wsUtilise le transport WebSocket
--quicUtilise MQTT over QUIC (sur les brokers compatibles)
TLS et WebSocket sécurisé
# 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 :

Latence de bout en bout
# 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 :

Sortie typique de pub
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
CompteurSignification
connect_succ / connect_failConnexions acceptées / échouées
connect_retried, reconnect_succNouvelles tentatives et reconnexions réussies
connection_refused, connection_timeout, unreachablePourquoi les connexions ont échoué
connection_idleConnexions devenues inactives
sub / sub_failAbonnements acceptés / refusés
pub / pub_succ / pub_failMessages envoyés / acquittés / échoués
pub_overrunUn client n'a pas pu tenir son intervalle de publication
pub_nosubLe broker a signalé l'absence de subscribers correspondants (MQTT 5)
recvMessages reçus par les subscribers
publish_latencyLatence 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 -n bien au-delà de -c avant de grosses exécutions conn.
  • 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.12 ou plusieurs machines, et élargissez la plage de ports locaux avec sysctl.
  • Mémoire. Ajoutez -l pour 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.