Prüfstände
Datum: 24. Juli 2026 · Protokoll: MQTT 3.1.1 · Werkzeug: eigener Lastclient cmd/loadtest auf Basis des projekteigenen Codecs, ohne fremde MQTT-Bibliothek.
Getestet wurde auf zwei Prüfständen, um das Verhalten des Brokers vom Einfluss der Umgebung zu trennen: Netzwerk gegen Loopback, bescheidene gegen starke Hardware.
| Prüfstand A — über das Netzwerk | Prüfstand B — Loopback | |
|---|---|---|
| CPU des Brokers | 12 Kerne | 2× Xeon E5-2690 v4 @ 2,6 GHz (28 Kerne / 56 Threads) |
| RAM des Brokers | 16 GB | 128 GB |
| Adresse | 192.168.1.84:1883 (LAN) | 127.0.0.1:1883 (Loopback) |
| Lastgenerator | Eigene Maschine im LAN | Dieselbe Maschine wie der Broker |
| Ephemere Ports des Clients | 16 384 (Standard) | 55 000 (erweitert) |
Zusammenfassung
- Latenz. Über das Netzwerk beträgt die Ende-zu-Ende-Latenz „Publisher → Broker → Subscriber“ bei normaler Last etwa 1 ms; über Loopback sind es 73 µs (~16× weniger, ohne Netzwerk).
- Verbindungen. Über das Netzwerk hielt der Broker 10 000 Sitzungen ohne Ausfälle (darüber hinaus stießen wir an die Portgrenze des Clients). Auf starker Hardware über Loopback: 30 000 ohne Ausfälle und ~41 000 bei einem Versuch mit 50 000 (die Grenze einer einzelnen Maschine, nicht des Brokers).
- Aufnahme. Der Spitzenwert über das Netzwerk lag bei ≈277 000 Nachrichten/s; über Loopback ist die Aufnahme geringer (≈185 000/s), weil der Generator mit dem Broker um Kerne konkurriert.
- Fan-out (Verteilung). Auf starker Hardware stellte der Broker ≈1 350 000 Nachrichten/s an Abonnenten zu (Fan-out ×100) gegenüber ≈22 000/s über das Netzwerk.
- Robustheit. Auf keinem Prüfstand stürzte der Broker ab oder blieb hängen. Bei Überlast werden QoS-0-Nachrichten an nachhinkende Abonnenten geordnet verworfen; das Broker-Log enthält über alle Läufe hinweg nicht einen einzigen Fehler.
Kapazität an gleichzeitigen Verbindungen
Jede Verbindung ist ein vollständiger Zyklus CONNECT → CONNACK mit Authentifizierung; anschließend wird die Sitzung offen gehalten (mit PINGREQ geprüft).
Prüfstand A — über das Netzwerk
| Ziel | Aufgebaut | Fehlgeschlagen | Aufbau p50 | p99 |
|---|---|---|---|---|
| 10 | 10 | 0 | 146 ms | 162 ms |
| 100 | 100 | 0 | 702 ms | 1,12 s |
| 1 000 | 1 000 | 0 | 4,21 s | 9,78 s |
| 5 000 | 5 000 | 0 | 4,64 s | 8,59 s |
| 10 000 | 10 000 | 0 | 4,92 s | 10,52 s |
| 15 000 | 14 879 | 121 | 7,43 s | 14,09 s |
Prüfstand B — Loopback (stufenweiser Aufbau)
| Ziel | Aufgebaut | Fehlgeschlagen | Aufbau p50 | p99 |
|---|---|---|---|---|
| 1 000 | 1 000 | 0 | 886 ms | 1,06 s |
| 10 000 | 10 000 | 0 | 903 ms | 1,55 s |
| 30 000 | 30 000 | 0 | 923 ms | 1,90 s |
| 50 000 | 41 219 | 0 | 984 ms | 1,90 s |
Analyse
- Über das Netzwerk bis 10 000 — kein einziger Ausfall; die 121 Fehlschläge bei 15 000 sind erschöpfte ephemere Ports des Clients (16 384). Das ist die Grenze des Generators, nicht des Brokers.
- Über Loopback hielt der Broker nach Erweiterung des Portbereichs 30 000 Sitzungen fehlerfrei; bei 50 000 waren am Ende des Haltens noch etwa 41 000 am Leben — beide Seiten teilen sich eine Maschine. Das Broker-Log blieb durchgehend sauber, ohne Fehler.
- Nebenbefund. Über Loopback löst ein zu scharfer Verbindungsstoß (1 000 gleichzeitige
dials) einconnection refusedaus — der Accept-Backlog läuft über: ohne Netzwerkverzögerung treffen alle SYN gleichzeitig ein. Ein stufenweiser Aufbau (200 auf einmal) beseitigt den Effekt vollständig. Über ein Netzwerk glättet die Latenz den Stoß von selbst.
Aufnahmedurchsatz
Ein Pool von Publishern veröffentlicht so schnell wie möglich; gemessen wird die Aufnahmerate des Brokers.
QoS 0 · 64 Byte Payload
| Publisher | Prüfstand A (Netzwerk) | Prüfstand B (Loopback) |
|---|---|---|
| 10 | 271 006/s | 185 012/s |
| 100 | 236 422/s | 101 457/s |
| 500 | 103 546/s | 125 324/s |
Die Aufnahme ist über das Netzwerk höher — nicht weil der Broker auf Prüfstand A schneller wäre, sondern weil der Generator dort auf einer eigenen Maschine läuft. Über Loopback teilen sich Client und Broker dieselben Kerne, was die gemeinsame Rate deckelt.
QoS 1 (mit PUBACK-Bestätigung) · 64 B
| Publisher | Prüfstand A (Netzwerk) | Prüfstand B (Loopback) |
|---|---|---|
| 10 | 10 292/s | 63 606/s |
| 100 | 22 085/s | 48 983/s |
Der Testclient für QoS 1 arbeitet synchron (er wartet nach jeder Nachricht auf ein PUBACK) und ist damit an die Umlaufzeit gebunden. Über Loopback ist die Umlaufzeit nahezu null, daher der Gewinn um das ~6-Fache. Das zeigt deutlich, dass die QoS-1-Zahlen von der Netzlatenz bestimmt werden und nicht vom Broker.
Durchlauf über Nachrichtengrößen · QoS 0 · 50 Publisher
| Größe | Prüfstand A (Netzwerk) | Prüfstand B (Loopback) |
|---|---|---|
| 64 B | 277 198/s · 17,7 MB/s | 101 961/s · 6,5 MB/s |
| 256 B | 124 997/s · 32,0 MB/s | 102 029/s · 26,1 MB/s |
| 1 024 B | 38 458/s · 39,4 MB/s | 102 151/s · 104,6 MB/s |
Zwei verschiedene Obergrenzen:
- Über das Netzwerk stoßen wir bei ≈40 MB/s an die Leitung: Wächst die Nachricht, fällt msg/s, während MB/s nahe am Limit bleibt.
- Über Loopback ist die Leitung riesig, also bleibt die Nachrichtenzahl konstant (~102 000/s bei 50 Verbindungen) und das Volumen steigt auf 104,6 MB/s. Hier ist die Verarbeitung je Nachricht (CPU) der Engpass, nicht die Bytes.
Ende-zu-Ende-Zustellung
In den Nachrichtenrumpf wird ein Zeitstempel eingebettet; gemessen werden die tatsächliche Zustellung und die Ende-zu-Ende-Latenz. Fan-out bedeutet die Zustellung an jeden Abonnenten, dessen Filter passt.
Prüfstand A — über das Netzwerk
| Szenario | Publish | Zustellung | Mittel / p50 / p99 |
|---|---|---|---|
| 10 Sub / 10 Pub / 100 Nachr./s — normal | 986/s | 9 863/s | 1,17 / 1,0 / 3,6 ms |
| 100 Sub / 10 Pub / ungedrosselt | 261 551/s | 22 351/s | 780 / 453 / 678 ms |
| 100 Sub / 10 Pub / 500 Nachr./s | 4 934/s | 12 150/s | 1,87 / 1,77 / 2,83 s |
| 1 000 Sub / 5 Pub / 100 Nachr./s | 494/s | 178 961/s | 2,29 s / 480 / 952 ms |
Prüfstand B — Loopback
| Szenario | Publish | Zustellung | Mittel / p50 / p99 |
|---|---|---|---|
| 10 Sub / 10 Pub / 100 Nachr./s — normal | 987/s | 9 867/s | 73 / ~0 / 555 µs |
| 100 Sub / 10 Pub / ungedrosselt | 47 557/s | 1 353 431/s | 514 / 135 / 251 ms |
| 100 Sub / 10 Pub / 500 Nachr./s | 3 608/s | 360 834/s | 17,1 / 10,5 / 71,6 ms |
| 1 000 Sub / 5 Pub / 100 Nachr./s | 494/s | 183 746/s | 4,73 / 4,54 / 15,1 ms |
Analyse
- Latenz bei normaler Last: 1,17 ms über das Netzwerk gegenüber 73 µs über Loopback. Der Unterschied ist der Netzwerkweg.
- Verteilung unter Last: Die starke Maschine stellte ≈1,35 Millionen Nachrichten/s an Abonnenten zu (Fan-out ×100) — zwei Größenordnungen über dem Netzwerk-Prüfstand (22 Tsd./s), wo sowohl Broker als auch Leitung klein sind.
- In Szenarien mit hohem Fan-out wird auch der Generator zum Engpass (alle Abonnenten in einem Prozess auf einer Maschine), daher sind die Spitzenwerte der Zustellung eine Untergrenze dessen, was der Broker kann.
Direkter Vergleich
| Kennwert | Prüfstand A — Netzwerk (12 Kerne) | Prüfstand B — Loopback (28 Kerne) |
|---|---|---|
| Verbindungen ohne Ausfälle | 10 000 | 30 000 |
| Spitzenwert Verbindungen | 14 879 (Clientgrenze) | ~41 000 (Grenze einer Maschine) |
| Aufnahme QoS 0 (64 B), Spitze | 271 006/s | 185 012/s |
| Aufnahme QoS 1 (64 B), Spitze | 22 085/s | 63 606/s |
| Volumengrenze | ≈40 MB/s (Leitung) | ≈105 MB/s (CPU) |
| Latenz (normal), Median | 1,0 ms | ~0 (73 µs im Mittel) |
| Zustellung bei Fan-out, Spitze | 22 351/s | 1 353 431/s |
| Fehler im Broker-Log | keine | keine |
Vorbehalte zur Methodik
- Die Aufnahmerate ist zwischen den Prüfständen nicht direkt vergleichbar: Auf Prüfstand B teilen sich Generator und Broker die Kerne; auf Prüfstand A ist der Generator eine eigene Maschine.
- Die Last kommt auf jedem Prüfstand von einer einzigen Clientmaschine; in manchen Szenarien (großes Fan-out, Zehntausende Verbindungen) ist diese Maschine der Engpass und nicht der Broker.
- Der Testclient für QoS 1 arbeitet synchron — die QoS-1-Zahlen bleiben hinter dem Möglichen des Brokers zurück.
- Systemkennwerte des Brokers (CPU/RAM während der Läufe) wurden nicht erfasst; der Zustand des Servers wird aus seinem Log (keine Fehler) und aus dem Verhalten der Clientseite geschlossen.
Nachvollziehen
Jeder Lauf wird aus einer einzigen loadtest-Binärdatei gestartet; nachfolgend die Befehle für die drei Modi.
go build -o loadtest ./cmd/loadtest
# Verbindungskapazität (stufenweiser Aufbau gegen Accept-Backlog)
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode conn -levels 1000,10000,30000,50000 -hold 3s -dial-concurrency 200
# Aufnahmedurchsatz
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pub -pubs 10 -qos 0 -payload 64 -duration 10s
# Ende-zu-Ende-Zustellung und Latenz
./loadtest -addr HOST:1883 -user myelx -pass *** \
-mode pubsub -subs 10 -pubs 10 -qos 0 -rate 100 -payload 64 -duration 10s