emqtt-bench (das Binary heißt emqtt_bench) ist ein Open-Source-Benchmark-Tool für MQTT von EMQ, in Erlang geschrieben, das von einer einzigen Maschine aus Zehntausende Verbindungen öffnen und Publish- sowie Subscribe-Last erzeugen kann. Es hat drei Befehle — conn, sub und pub — und eine lange Liste von Flags. Diese Anleitung erklärt jeden Befehl, die Flags, auf die es wirklich ankommt, TLS und WebSocket, Latenzmessung und wie du die Ausgabe liest.
Für die übergeordnete Methode — was du misst und wie du einen Benchmark planst — siehe MQTT-Broker-Lasttests. Diese Seite ist die Referenz zum Tool selbst.
Installieren oder mit Docker starten
Am schnellsten geht es mit dem Docker-Image, dessen Entrypoint emqtt_bench ist:
docker run --rm -it emqx/emqtt-bench pub --helpFür lange oder sehr große Läufe vermeidet eine native Installation den Netzwerk-Overhead von Docker. Vorgebaute Pakete gibt es auf der Release-Seite des Projekts bei GitHub. Zum Bauen aus dem Quellcode brauchst du ein aktuelles Erlang/OTP und libatomic:
git clone https://github.com/emqx/emqtt-bench.git
cd emqtt-bench
make # BUILD_WITHOUT_QUIC=1 make, falls der QUIC-Build fehlschlägt
./emqtt_bench conn --helpPrüfe vor jedem Benchmark Host, Port und Zugangsdaten von Hand mit einem einzelnen Client im Online-MQTT-Client. Scheitert eine Verbindung, scheitern zweitausend nur schneller. Die Beispiele nutzen broker.connectmq.com, einen geteilten Endpoint für schnelle Checks; echte Benchmarks fährst du gegen deine eigene private Broker-Instanz, indem du -h und die Zugangsdaten änderst.
Optionen für alle Befehle
| Flag | Bedeutung | Standard |
|---|---|---|
-h, --host | Broker-Host; eine kommagetrennte Liste verteilt die Clients auf mehrere Hosts | localhost |
-p, --port | Broker-Port | 1883 |
-V, --version | MQTT-Protokollversion: 3 (3.1), 4 (3.1.1) oder 5 | 5 |
-c, --count | Anzahl der zu startenden Clients | 200 |
-i, --interval | Millisekunden zwischen neuen Verbindungen | 10 |
-R, --connrate | Verbindungen pro Sekunde; 0 fällt auf -i zurück | 0 |
-u, -P | Benutzername und Passwort | keine |
-k, --keepalive | Keep Alive in Sekunden | 300 |
-C, --clean | Clean Session / Clean Start | true |
-x, --session-expiry | MQTT-5-Session-Expiry-Intervall in Sekunden | 0 |
--prefix | Präfix der Client-ID (ohne Zufallssuffix, wenn gesetzt) | <host>_bench_<cmd>_<random>_<n> |
--shortids | Kurze Client-IDs: die Sequenznummer oder Präfix + Nummer | false |
-n, --startnumber | Erste Sequenznummer; vermeidet ID-Kollisionen zwischen mehreren Instanzen | 0 |
--ifaddr | Lokale IP-Adresse(n) zum Binden, kommagetrennt | Systemstandard |
--reconnect | Reconnect-Versuche nach einem Verbindungsabbruch | 0 (aus) |
--num-retry-connect | Wiederholungen beim ersten Verbindungsaufbau | 0 |
-l, --lowmem | Low-Memory-Modus: weniger RAM pro Client, mehr CPU | aus |
Zwei Details sorgen oft für Verwirrung. Erstens ist die Standard-Protokollversion MQTT 5; übergib -V 4, um einen Broker oder eine Konfiguration zu testen, die nur 3.1.1 spricht. Zweitens ist der Keep-Alive-Standard von 300 s viel länger als bei den meisten Geräten; setze -k auf den Wert deiner Flotte, wenn du das Verhalten bei inaktiven Verbindungen testest.
Client-IDs müssen pro Broker eindeutig sein. Wenn du mehrere emqtt-bench-Prozesse gegen denselben Broker laufen lässt, gib jedem ein eigenes --prefix oder einen eigenen -n-Bereich — doppelte IDs verursachen Session-Takeovers, die wie zufällige Verbindungsabbrüche aussehen. ID-Formate kannst du mit dem Client-ID-Generator ausprobieren.
conn: Verbindungskapazität
conn verbindet nur und hält die Verbindungen. Es beantwortet die Frage: „Wie viele gleichzeitige Clients hält der Broker aus, und wie schnell nimmt er sie an?“
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"Beobachte, wie connect_succ auf den Zielwert steigt und connect_fail bei null bleibt. Einen Reconnect-Sturm — alle Geräte kommen nach einem Ausfall gleichzeitig zurück — simulierst du mit einem höheren -R. Weitere Szenarien findest du in der Anleitung zum Verbindungs-Stresstest.
sub: Subscriber
sub verbindet Clients, subscribt jeden auf ein Topic und zählt, was ankommt.
| Flag | Bedeutung | Standard |
|---|---|---|
-t, --topic | Topic-Filter mit Platzhaltern (siehe unten) | erforderlich |
-q, --qos | QoS der Subscription | 0 |
--payload-hdrs | Vom Publisher hinzugefügte Header auswerten (ts, cnt64) | keine |
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: Publisher
pub verbindet Clients und publisht in einem festen Intervall pro Client.
| Flag | Bedeutung | Standard |
|---|---|---|
-t, --topic | Ziel-Topic mit Platzhaltern | erforderlich |
-I, --interval_of_msg | Millisekunden zwischen Nachrichten pro Client | 1000 |
-s, --size | Payload-Größe in Byte | 256 |
-m, --message | Literal-Payload oder template://<file> | Zufallsbytes |
-q, --qos | Publish-QoS | 0 |
-r, --retain | Retain-Flag setzen | false |
-L, --limit | Nach so vielen Nachrichten stoppen; 0 = unbegrenzt | 0 |
-F, --inflight | Max. unbestätigte QoS-1/2-Nachrichten pro Client; 0 = unbegrenzt | 1 |
-w, --wait-before-publishing | Erst publishen, wenn alle Publisher eine Verbindung versucht haben | false |
--payload-hdrs | Payload mit ts (Timestamp) und/oder cnt64 (Zähler) einleiten | keine |
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"Die Zielrate ist Clients × (1000 / -I). Achte auf -F: Mit dem Standard-Inflight-Fenster von 1 wartet jeder QoS-1-Client auf jedes PUBACK, bevor er die nächste Nachricht sendet — bei hoher Latenz erreicht ein Client sein Intervall also nie. Zählt pub_overrun hoch, konnte der Client seinen Takt nicht halten; erhöhe -F oder senke die Rate. Strategien für Durchsatztests findest du in der Anleitung zum MQTT-Durchsatztest.
Topic-Platzhalter
Platzhalter in -t lassen einen einzigen Befehl viele verschiedene Topics erzeugen:
| Platzhalter | Wird ersetzt durch |
|---|---|
%i | Sequenznummer des Clients (inklusive -n-Offset) |
%c | Client-ID |
%u | Den mit -u angegebenen Benutzernamen |
%s | Sequenznummer der Nachricht (nur pub) |
%rand_N | Zufällige Ganzzahl von 1 bis N |
Mit %i auf beiden Seiten — pub -t 'testmqtt/bench/%i/data' und sub -t 'testmqtt/bench/%i/data' mit gleichem -c — bildet Publisher N ein Paar mit Subscriber N: Eins-zu-eins-Routing. Ein einzelner Subscriber auf testmqtt/bench/+/data misst dagegen Fan-in, viele Subscriber auf einem Topic messen Fan-out. Prüfe deine Filter mit dem Topic Matcher.
TLS, WebSockets und QUIC
| Flag | Bedeutung |
|---|---|
-S, --ssl | TLS aktivieren |
--ssl-version | Eine TLS-Version erzwingen (impliziert --ssl) |
--cacertfile | CA-Bundle zur Prüfung des Brokers |
--certfile, --keyfile | Client-Zertifikat und -Schlüssel (Mutual TLS) |
--ciphers | Cipher Suites einschränken |
--ws | WebSocket-Transport nutzen |
--quic | MQTT über QUIC nutzen (bei Brokern, die es unterstützen) |
# MQTT über 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 über sicheren WebSocket
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 hat kein eigenes Flag für den WebSocket-Pfad; der darunterliegende emqtt-Client nutzt /mqtt, was zum Endpoint in diesen Beispielen passt. Derselbe conn-Lauf über 1883 und 8883 zeigt die Kosten des Handshakes direkt — siehe MQTT-TLS-Performancetests.
Latenz messen
Starte Subscriber und Publisher mit demselben --payload-hdrs ts. Der Publisher schreibt einen Millisekunden-Timestamp an den Anfang jedes Payloads; der Subscriber zieht ihn beim Empfang von seiner eigenen Uhr ab:
# 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"Der Subscriber gibt dann eine Zeile publish_latency avg=…ms aus. Das ist ein Durchschnitt; für Perzentile aktivierst du --prometheus (stellt ein e2e_latency-Histogramm bereit) oder nutzt das Skript aus der Lasttest-Anleitung. Da der Timestamp von der Uhr des Publishers stammt, lass beide auf einer Maschine laufen oder halte die Uhren der Maschinen synchron.
Die Ausgabe lesen
Jede Sekunde gibt emqtt-bench pro geändertem Zähler eine Zeile im Format <Zeit> <Zähler> total=<n> rate=<n>/sec aus:
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| Zähler | Bedeutung |
|---|---|
connect_succ / connect_fail | Angenommene / fehlgeschlagene Verbindungen |
connect_retried, reconnect_succ | Wiederholungen und erfolgreiche Reconnects |
connection_refused, connection_timeout, unreachable | Warum Verbindungen fehlschlugen |
connection_idle | Inaktiv gewordene Verbindungen |
sub / sub_fail | Angenommene / abgelehnte Subscriptions |
pub / pub_succ / pub_fail | Gesendete / bestätigte / fehlgeschlagene Nachrichten |
pub_overrun | Ein Client konnte sein Publish-Intervall nicht halten |
pub_nosub | Der Broker meldete keine passenden Subscriber (MQTT 5) |
recv | Von Subscribern empfangene Nachrichten |
publish_latency | Durchschnittliche End-to-End-Latenz (mit --payload-hdrs ts) |
Das gesunde Muster: Die Raten von pub und recv entsprechen deinem Ziel und einander, pub_overrun bleibt bei null, und keine Fehlerzähler tauchen auf. Ein steigender connection_timeout oder connect_fail nahe einer runden Zahl (1.024, 65.535) deutet meist auf Limits am Lastgenerator hin. Reason Codes des Brokers schlägst du im Reason-Code-Tool nach.
Den Lastgenerator skalieren
- File Descriptors. Erhöhe
ulimit -nvor großenconn-Läufen deutlich über-c. - Ports. Eine Quell-IP öffnet nur etwa 64K Verbindungen zu einer Broker-Adresse und einem Port. Nutze
--ifaddr 10.0.0.11,10.0.0.12oder mehrere Maschinen und erweitere den lokalen Portbereich persysctl. - Speicher. Füge
-lfür sehr viele Clients hinzu, auf Kosten von mehr CPU. - CPU. Liegt der Generator über etwa 80 % CPU, beschreiben deine Zahlen den Generator, nicht den Broker.
Benchmark-Traffic im Online-Client ansehen
emqtt-bench ist der schnellste Weg, über die Kommandozeile realistische Verbindungs- und Nachrichtenlast auf einen MQTT-Broker zu bringen. Lerne die Handvoll Flags, die die Last formen — -c, -R, -I, -q, -F und die Topic-Platzhalter —, stelle sicher, dass TLS und Protokollversion zur Produktion passen, und lies die Zähler als Raten, die du von Lauf zu Lauf vergleichen kannst.
Häufig gestellte Fragen
Was ist der Unterschied zwischen -i und -R bei emqtt-bench?
-i (--interval) ist die Pause in Millisekunden zwischen neuen Verbindungen, Standard 10. -R (--connrate) setzt stattdessen eine Verbindungsrate pro Sekunde; ist sie 0 (Standard), nutzt emqtt-bench wieder das Intervall.
Wie messe ich Latenz mit emqtt-bench?
Starte Subscriber und Publisher mit derselben Option --payload-hdrs ts. Der Publisher stellt jedem Payload einen Millisekunden-Timestamp voran, und der Subscriber gibt eine publish_latency-Zeile mit der durchschnittlichen End-to-End-Latenz aus. Lass beide auf einer Maschine laufen oder halte die Uhren synchron.
Warum stoppt emqtt-bench bei etwa 64.000 Verbindungen?
Eine Quell-IP kann nur etwa 64K TCP-Verbindungen zur selben Broker-Adresse und zum selben Port öffnen. Verteile die Clients mit --ifaddr auf mehrere lokale Adressen oder nutze mehrere Maschinen, und erhöhe ulimit -n.



