Broker-Tests

emqtt-bench-Anleitung: alle Befehle und Flags erklärt

Komplette emqtt-bench-Anleitung: Modi conn, pub und sub, alle wichtigen Flags, TLS- und WebSocket-Optionen, Latenz-Header und wie du die Ausgabezähler liest.

Aktualisiert · 10 Min. Lesezeit

emqtt-bench-Anleitung: alle Befehle und Flags erklärt

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:

Mit Docker starten
docker run --rm -it emqx/emqtt-bench pub --help

Fü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:

Aus dem Quellcode bauen
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 --help

Prü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

FlagBedeutungStandard
-h, --hostBroker-Host; eine kommagetrennte Liste verteilt die Clients auf mehrere Hostslocalhost
-p, --portBroker-Port1883
-V, --versionMQTT-Protokollversion: 3 (3.1), 4 (3.1.1) oder 55
-c, --countAnzahl der zu startenden Clients200
-i, --intervalMillisekunden zwischen neuen Verbindungen10
-R, --connrateVerbindungen pro Sekunde; 0 fällt auf -i zurück0
-u, -PBenutzername und Passwortkeine
-k, --keepaliveKeep Alive in Sekunden300
-C, --cleanClean Session / Clean Starttrue
-x, --session-expiryMQTT-5-Session-Expiry-Intervall in Sekunden0
--prefixPräfix der Client-ID (ohne Zufallssuffix, wenn gesetzt)<host>_bench_<cmd>_<random>_<n>
--shortidsKurze Client-IDs: die Sequenznummer oder Präfix + Nummerfalse
-n, --startnumberErste Sequenznummer; vermeidet ID-Kollisionen zwischen mehreren Instanzen0
--ifaddrLokale IP-Adresse(n) zum Binden, kommagetrenntSystemstandard
--reconnectReconnect-Versuche nach einem Verbindungsabbruch0 (aus)
--num-retry-connectWiederholungen beim ersten Verbindungsaufbau0
-l, --lowmemLow-Memory-Modus: weniger RAM pro Client, mehr CPUaus

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?“

5.000 Clients mit 500 Verbindungen pro Sekunde
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.

FlagBedeutungStandard
-t, --topicTopic-Filter mit Platzhaltern (siehe unten)erforderlich
-q, --qosQoS der Subscription0
--payload-hdrsVom Publisher hinzugefügte Header auswerten (ts, cnt64)keine
100 Subscriber mit je einem Topic
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.

FlagBedeutungStandard
-t, --topicZiel-Topic mit Platzhalternerforderlich
-I, --interval_of_msgMillisekunden zwischen Nachrichten pro Client1000
-s, --sizePayload-Größe in Byte256
-m, --messageLiteral-Payload oder template://<file>Zufallsbytes
-q, --qosPublish-QoS0
-r, --retainRetain-Flag setzenfalse
-L, --limitNach so vielen Nachrichten stoppen; 0 = unbegrenzt0
-F, --inflightMax. unbestätigte QoS-1/2-Nachrichten pro Client; 0 = unbegrenzt1
-w, --wait-before-publishingErst publishen, wenn alle Publisher eine Verbindung versucht habenfalse
--payload-hdrsPayload mit ts (Timestamp) und/oder cnt64 (Zähler) einleitenkeine
100 Publisher mit je 10 msg/s = 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"

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:

PlatzhalterWird ersetzt durch
%iSequenznummer des Clients (inklusive -n-Offset)
%cClient-ID
%uDen mit -u angegebenen Benutzernamen
%sSequenznummer der Nachricht (nur pub)
%rand_NZufä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

FlagBedeutung
-S, --sslTLS aktivieren
--ssl-versionEine TLS-Version erzwingen (impliziert --ssl)
--cacertfileCA-Bundle zur Prüfung des Brokers
--certfile, --keyfileClient-Zertifikat und -Schlüssel (Mutual TLS)
--ciphersCipher Suites einschränken
--wsWebSocket-Transport nutzen
--quicMQTT über QUIC nutzen (bei Brokern, die es unterstützen)
TLS und sicherer WebSocket
# 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:

End-to-End-Latenz
# 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:

Typische pub-Ausgabe
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ählerBedeutung
connect_succ / connect_failAngenommene / fehlgeschlagene Verbindungen
connect_retried, reconnect_succWiederholungen und erfolgreiche Reconnects
connection_refused, connection_timeout, unreachableWarum Verbindungen fehlschlugen
connection_idleInaktiv gewordene Verbindungen
sub / sub_failAngenommene / abgelehnte Subscriptions
pub / pub_succ / pub_failGesendete / bestätigte / fehlgeschlagene Nachrichten
pub_overrunEin Client konnte sein Publish-Intervall nicht halten
pub_nosubDer Broker meldete keine passenden Subscriber (MQTT 5)
recvVon Subscribern empfangene Nachrichten
publish_latencyDurchschnittliche 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 -n vor großen conn-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.12 oder mehrere Maschinen und erweitere den lokalen Portbereich per sysctl.
  • Speicher. Füge -l fü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.