In MQTT ist das Topic das Einzige, was Publisher und Subscriber miteinander verbindet. Es gibt keine Queues oder Exchanges zu konfigurieren – der Broker gleicht einfach das Topic jeder Nachricht mit allen Subscription-Filtern ab. Damit wird das Topic-Design zum Rückgrat deines Systems: Es bestimmt, was Clients abonnieren können, wie Berechtigungen formuliert werden und wie leicht du später neue Consumer hinzufügen kannst.
Topic-Grundlagen
Ein Topic-Name ist ein UTF-8-String aus Ebenen (Levels), die durch einen Schrägstrich getrennt sind:
building-a/floor-3/room-12/temperature
vehicles/truck-0042/gps
acme/devices/sensor-17/status- Topics unterscheiden Groß- und Kleinschreibung.
Home/Kitchenundhome/kitchensind verschiedene Topics. - Keine Registrierung nötig. Ein Topic existiert in dem Moment, in dem jemand daran publisht.
- Jedes Zeichen zählt. Ein führender Schrägstrich erzeugt eine leere erste Ebene, daher ist
/home/kitchennicht dasselbe wiehome/kitchen. Leerzeichen sind erlaubt, sorgen aber für endlose Verwirrung. - Größe. Topic-Namen müssen mindestens ein Zeichen und höchstens 65.535 Bytes lang sein und dürfen kein Null-Zeichen enthalten.
Wildcards: + und #
Subscriber verwenden Topic-Filter, die zwei Wildcards enthalten dürfen. Publisher nutzen immer konkrete Topic-Namen – Wildcards in einem PUBLISH sind ein Protokollverstoß.
Single-Level-Wildcard: +
+ passt auf genau eine Ebene. Es muss eine ganze Ebene belegen (sensor+ ist ungültig), darf aber überall und mehrfach vorkommen.
| Filter | Passt auf | Passt nicht auf |
|---|---|---|
home/+/temperature | home/kitchen/temperature | home/kitchen/oven/temperature |
+/+/status | acme/sensor-17/status | acme/status |
home/+ | home/kitchen | home, home/kitchen/light |
Multi-Level-Wildcard: #
# passt auf beliebig viele Ebenen – auch auf null – und muss das letzte Zeichen des Filters sein, auf einer eigenen Ebene. home/# passt auf home/kitchen, home/kitchen/light/state und auch auf die übergeordnete Ebene home selbst. Filter wie home/#/light oder home# sind ungültig.
Ein einzelnes # abonniert jedes Topic auf dem Broker (außer $-Topics). Zum Debuggen deines eigenen privaten Brokers ist das nützlich, auf einem öffentlichen Broker wirst du damit aber vom Traffic anderer Leute überflutet.
$SYS und andere $-Topics
Topics, die mit $ beginnen, sind für den Broker reserviert. Am bekanntesten ist $SYS/, wo viele Broker (Mosquitto, EMQX und andere) Statistiken wie verbundene Clients, Nachrichtenraten und Uptime veröffentlichen. Die genauen Topics sind Broker-spezifisch – die Spezifikation reserviert nur das Präfix.
Wildcards auf der ersten Ebene passen nicht auf $-Topics: # und +/monitor liefern niemals $SYS/...-Nachrichten. Abonniere sie explizit:
mosquitto_sub -h test.mosquitto.org -t '$SYS/broker/clients/connected' -vMQTT 5 bringt ein weiteres reserviertes Präfix mit: Shared Subscriptions verwenden $share/<group>/<filter>. Alle Subscriber derselben Gruppe teilen sich den Stream, wobei jede Nachricht nur an ein Mitglied geht – ein einfacher Weg, Consumer per Load Balancing zu verteilen. Weitere MQTT-5-Neuerungen wie Topic Aliases findest du unter MQTT 5 vs. 3.1.1.
Eine Topic-Hierarchie entwerfen
Eine gute Hierarchie geht vom Allgemeinen zum Speziellen, sodass Wildcards am Ende sinnvolle Gruppen auswählen. Ein verbreitetes Muster ist:
<org-or-app>/<site>/<device-type>/<device-id>/<measurement-or-channel>
acme/berlin/thermostat/th-0193/temperature
acme/berlin/thermostat/th-0193/setpoint/set
acme/berlin/thermostat/th-0193/statusMit diesem Aufbau gilt:
acme/berlin/#liefert einem Standort-Dashboard alles aus Berlin.acme/+/thermostat/+/temperatureliefert einem Analytics-Service jeden Thermostat-Messwert.acme/berlin/thermostat/th-0193/#liefert den kompletten Stream eines einzelnen Geräts.
Best Practices
- Beginne nicht mit einem Schrägstrich. Er fügt eine sinnlose leere Ebene hinzu.
- Nutze Kleinbuchstaben, ASCII und Bindestriche. Vermeide Leerzeichen und gemischte Groß-/Kleinschreibung; sie führen zu subtilen Fehlzuordnungen.
- Nimm die Geräte- oder Client-ID ins Topic auf. Das macht Zugriffskontrolle pro Client einfach (viele Broker können die Client-ID oder den Benutzernamen in ACL-Patterns einsetzen).
- Trenne Daten, Befehle und Zustand. Zum Beispiel
.../temperaturefür Telemetrie,.../setpoint/setfür Befehle und.../statusfür Retained-Zustand oder Präsenz per Last Will. - Halte Topics kurz, aber aussagekräftig. Das Topic wird mit jeder Nachricht übertragen (außer du nutzt Topic Aliases aus MQTT 5), daher kosten sehr lange Namen auf schmalbandigen Verbindungen Bandbreite.
- Kodiere keine Daten im Topic. Werte gehören in die Payload; ein Topic pro Wert erzeugt unbegrenzt viele Topics und massenhaft Retained Messages.
- Versioniere dein Schema, falls es sich ändern kann. Ein Präfix wie
v1/lässt alte und neue Geräte während einer Migration nebeneinander existieren. - Vermeide breite Subscriptions in Produktion. Wenn ein Backend-Service
#abonniert, wird jede Nachricht auf dem Broker zu seinem Problem.
Häufige Fehler bei Topics
- Erwarten, dass
a/+aufapasst. Tut es nicht –+verlangt, dass eine Ebene vorhanden ist. Nutzea/#, wenn du auch die übergeordnete Ebene willst. - Abschließende Schrägstriche.
home/kitchen/hat eine leere letzte Ebene und ist ein anderes Topic alshome/kitchen. - Überlappende Subscriptions. Abonniert ein Client sowohl
home/#als auchhome/+/temperature, erlaubt die Spezifikation dem Broker, entweder eine einzige Kopie oder eine Kopie pro passender Subscription zuzustellen – manche Broker liefern dir also Duplikate. Halte Subscriptions nach Möglichkeit überschneidungsfrei. - Gemischte ID-Formate. Wenn manche Geräte als
Sensor_17und andere alssensor-17publishen, muss jeder Filter und jede ACL-Regel beides abdecken. Normalisiere IDs schon beim Provisioning. - Topics als Datenbank behandeln. Broker sind fürs Routing optimiert, nicht für Abfragen. Wenn du Historie brauchst, lass einen Consumer abonnieren und die Nachrichten in eine Datenbank schreiben.
Topics und Zugriffskontrolle
Broker autorisieren Publish- und Subscribe-Operationen pro Topic, deine Hierarchie ist also gleichzeitig dein Berechtigungsmodell. Schreibt jedes Gerät nur unterhalb von acme/<site>/<type>/<device-id>/, kannst du ihm genau diesen Teilbaum freigeben und sonst nichts. Sind die Topics flach oder inkonsistent, lassen sich keine engen Regeln mehr schreiben, und Teams geben am Ende jedem # frei.
Probier es selbst aus
Öffne den Online-MQTT-Client, abonniere testmqtt/demo/+/temperature und publishe an testmqtt/demo/kitchen/temperature und testmqtt/demo/kitchen/oven/temperature. Nur die erste Nachricht kommt an – genau wie es die +-Regel vorhersagt.
Im Online-MQTT-Client ausprobieren
Häufig gestellte Fragen
Was ist der Unterschied zwischen + und # in MQTT?
Die Wildcard + passt auf genau eine Topic-Ebene und darf überall im Filter stehen. Die Wildcard # passt auf beliebig viele Ebenen, auch auf null, und muss das letzte Zeichen des Filters sein.
Kann ich an ein Topic publishen, das eine Wildcard enthält?
Nein. Wildcards sind nur in Subscription-Filtern erlaubt. Ein PUBLISH mit + oder # im Topic-Namen ist ein Protokollfehler, und der Broker schließt die Verbindung.
Enthält eine Subscription auf # auch $SYS-Topics?
Nein. Filter, die mit einer Wildcard beginnen, passen nicht auf Topics, die mit $ anfangen. Um Broker-Statistiken zu erhalten, musst du explizit abonnieren, zum Beispiel $SYS/#.