MQTT-Grundlagen

MQTT Receive Maximum: Flusskontrolle für langsame Geräte in MQTT 5

Receive Maximum ist die eingebaute Flusskontrolle von MQTT 5. Es begrenzt, wie viele unbestätigte QoS-1- und QoS-2-Nachrichten gleichzeitig unterwegs sein dürfen, damit langsame Geräte nach einem Reconnect nicht überrollt werden.

Illustration zu MQTT Receive Maximum mit einem begrenzten Fenster unbestätigter Nachrichten, die von einem Broker zu einem kleinen Mikrocontroller fließen
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

MQTT Receive Maximum ist die Einstellung in MQTT 5, mit der Sie der Gegenseite mitteilen, wie viele QoS-1- und QoS-2-Nachrichten gleichzeitig „in flight“, also unbestätigt, unterwegs sein dürfen. In diesem Leitfaden erfahren Sie, wie dieses Flusskontrollfenster in beide Richtungen funktioniert, warum es für Mikrocontroller und Nachrichtenwellen nach einem Reconnect wichtig ist und wie Sie es in mosquitto, Python und Node.js setzen.

Welches Problem Receive Maximum löst

MQTT 3.1.1 hatte keine standardisierte Flusskontrolle. Ein Broker konnte QoS-1-Nachrichten so schnell an einen Client schicken, wie es die TCP-Verbindung zuließ, und der Client musste jede einzelne puffern, bis er das PUBACK gesendet hatte. Auf einem Server klappt das, aber einem Mikrocontroller mit wenigen Kilobyte freiem RAM kann der Speicher ausgehen, er verliert Nachrichten oder stürzt ab. Am schlimmsten ist es direkt nach einem Reconnect, wenn eine Persistent Session einen Rückstau gepufferter Nachrichten auf einmal freigibt.

Broker und Bibliotheken erfanden eigene „Max in-flight“-Einstellungen, um damit umzugehen, doch diese wurden nicht ausgehandelt, sodass keine Seite das Limit der anderen kannte. MQTT 5 hat die Idee als Property Receive Maximum standardisiert.

So funktioniert das Fenster von MQTT Receive Maximum

Receive Maximum ist eine Zwei-Byte-Ganzzahl von 1 bis 65.535, die jede Seite angeben kann:

  • Der Client sendet sie im CONNECT: „Broker, schick mir nicht mehr als N unbestätigte QoS-1/2-PUBLISH-Pakete.“
  • Der Broker sendet sie im CONNACK: „Client, schick mir nicht mehr als N unbestätigte QoS-1/2-PUBLISH-Pakete.“

Fehlt die Property, gilt der Standardwert 65.535, was praktisch „kein Limit“ bedeutet. Der Wert 0 ist nicht erlaubt.

Was als „in flight“ zählt

Pakettyp Zählt gegen das Fenster? Freigegeben, wenn
QoS-0-PUBLISH Nein Nicht zutreffend
QoS-1-PUBLISH Ja PUBACK empfangen
QoS-2-PUBLISH Ja PUBCOMP empfangen (oder PUBREC mit Fehler-Reason-Code)
Retained Message, die beim Abonnieren gesendet wird Ja, bei Zustellung mit QoS 1 oder 2 Normale Bestätigung
Gepufferte Offline-Nachrichten Ja, bei QoS 1 oder 2 Normale Bestätigung

Der Sender führt einen Zähler (die Spezifikation nennt ihn Send Quota). Jedes QoS-1- oder QoS-2-PUBLISH verringert ihn, jede abschließende Bestätigung erhöht ihn. Erreicht er null, muss der Sender das Senden von QoS-1- und QoS-2-Nachrichten einstellen und warten. QoS-0-Nachrichten darf er weiterhin senden, und laut Spezifikation darf er auch weiter PINGREQ schicken, sodass Keep Alive unbeeinträchtigt bleibt.

Was passiert, wenn das Limit überschritten wird

Ignoriert ein Sender das Fenster und erhält der Empfänger mehr unbestätigte QoS-1/2-Nachrichten, als er angekündigt hat, sollte der Empfänger die Verbindung mit dem Reason Code 0x93 (Receive Maximum exceeded) trennen. In der Praxis sieht man das selten, weil gängige Bibliotheken das Fenster automatisch einhalten. Wenn es doch auftritt, deutet es fast immer auf eine selbst geschriebene oder sehr alte Client-Implementierung hin.

Warum es für langsame Geräte wichtig ist

Nehmen Sie einen ESP32, der sich nach einem zehnminütigen WLAN-Ausfall neu verbindet. Seine Session hält 200 gepufferte QoS-1-Konfigurationsupdates. Ohne Flusskontrolle kann der Broker alle 200 auf einmal schicken. Mit einem Receive Maximum von 5 sendet der Broker fünf, wartet auf die PUBACKs und schickt mit jeder eintreffenden Bestätigung weitere. Der Speicherverbrauch bleibt begrenzt, die Verarbeitung kommt hinterher und das Gerät bleibt reaktionsfähig.

Das Fenster liefert auch natürlichen Gegendruck (Back-Pressure) für Backend-Consumer: Sendet ein Worker das PUBACK erst, nachdem er eine Nachricht in seine Datenbank geschrieben hat, verhindert ein kleines Receive Maximum, dass der Broker mehr Arbeit auftürmt, als der Worker bewältigen kann. Ein typisches Beispiel aus der Fertigung ist ein Historian- oder MES-Konnektor, der Maschinendaten aus dem Unified Namespace (UNS) eines Werks in eine Datenbank schreibt. Das ergänzt MQTT Shared Subscriptions sinnvoll, bei denen sich mehrere Worker einen Nachrichtenstrom teilen und das Fenster jedes Workers seinen Anteil an unbestätigter Arbeit begrenzt.

Receive Maximum in Clients setzen

Testen Sie gegen den öffentlichen MQTT-Broker unter broker.connectmq.com mit einem eindeutigen Präfix wie connectmq/demo/r2m6/.... Der öffentliche MQTT-Broker ist für Tests gedacht und für alle offen, verwenden Sie also Dummy-Payloads.

mosquitto_sub

mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i recvmax-demo-r2m6 -q 1 -v -d \
  -D connect receive-maximum 5 \
  -t 'connectmq/demo/r2m6/#'

Die Ausgabe von -d zeigt die gesendeten CONNECT-Properties und die vom Broker zurückgegebenen CONNACK-Properties, einschließlich seines eigenen Receive Maximum, falls er eines gesetzt hat.

Python (paho-mqtt 2.x)

import time
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

def on_connect(client, userdata, flags, reason_code, properties):
    server_rm = getattr(properties, "ReceiveMaximum", 65535)
    print("Connected:", reason_code, "| broker receive maximum:", server_rm)
    client.subscribe("connectmq/demo/r2m6/#", qos=1)

def on_message(client, userdata, msg):
    # Langsames Gerät simulieren; paho sendet PUBACK, nachdem dieser Callback zurückkehrt
    time.sleep(0.5)
    print("Handled", msg.topic, msg.payload.decode())

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="recvmax-py-r2m6",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message

# Begrenzen, was *wir* gleichzeitig senden (ausgehendes Fenster)
client.max_inflight_messages_set(10)

# Den Broker bitten zu begrenzen, was *er* an uns sendet (eingehendes Fenster)
props = Properties(PacketTypes.CONNECT)
props.ReceiveMaximum = 5

client.connect("broker.connectmq.com", 1883, keepalive=60, properties=props)
client.loop_forever()

Veröffentlichen Sie aus einem anderen Terminal eine Nachrichtenwelle und beobachten Sie, wie die Nachrichten in gleichmäßigem Tempo eintreffen:

for i in $(seq 1 30); do
  mosquitto_pub -h broker.connectmq.com -p 1883 -i burst-r2m6 \
    -q 1 -t 'connectmq/demo/r2m6/burst' -m "msg $i"
done

Beachten Sie, dass time.sleep im Callback auch die Netzwerkschleife von paho blockiert. Für diese Demonstration ist das in Ordnung, in der Produktion sollten Sie langsame Arbeit aber in einen separaten Thread auslagern und die Schleife frei halten, sonst verzögern sich die Keep-Alive-Pings.

Node.js (MQTT.js v5)

const mqtt = require("mqtt");

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "recvmax-node-r2m6",
  protocolVersion: 5,
  properties: { receiveMaximum: 5 },
});

client.on("connect", (connack) => {
  console.log("broker properties:", connack.properties);
  client.subscribe("connectmq/demo/r2m6/#", { qos: 1 });
});

client.on("message", (topic, payload) => {
  console.log(topic, payload.toString());
});

Den passenden Wert für Receive Maximum wählen

Client Empfohlener Wert Warum
Mikrocontroller (ESP32, ESP8266) 1 bis 10 Begrenzter RAM, sequenzielle Verarbeitung
Raspberry-Pi- oder Industrie-Edge-Gateway 10 bis 50 Mehr Speicher, aber weiterhin bescheidene CPU
Backend-Worker, der in eine Datenbank schreibt Etwa die Zahl paralleler Schreibvorgänge, die er dauerhaft schafft Gegendruck entspricht dem realen Durchsatz
Dashboard mit Live-Werten Standardwert Überwiegend QoS-0-Verkehr, der nicht begrenzt wird

Ein Wert von 1 erzwingt strikte Einzelverarbeitung, was auch die Logik für die Reihenfolge vereinfachen kann, kostet aber auf Verbindungen mit hoher Latenz Durchsatz. Jeder Slot benötigt einen Roundtrip, sodass ein winziges Fenster auf einer Mobilfunkverbindung mit hoher Latenz den Durchsatz spürbar deckeln kann. Messen Sie mit Ihrem realen Verkehr.

Receive Maximum und Nachrichtenreihenfolge

Ein Fenster größer als 1 bricht die Reihenfolgegarantien von MQTT nicht: Der Broker sendet die Nachrichten eines Topics weiterhin in der Reihenfolge, in der er sie empfangen hat, und der Client empfängt sie in dieser Reihenfolge. Was sich ändert, ist nur, wie viele gleichzeitig auf eine Bestätigung warten können. Bestätigt Ihre Anwendung Nachrichten in anderer Reihenfolge, etwa weil sie sie an einen Thread-Pool übergibt, liegt die Verarbeitungsreihenfolge in Ihrer Verantwortung, nicht in der des Protokolls. Das Verhalten ist dasselbe, ob Sie sich mit einem ConnectMQ-Broker, einem lokalen Mosquitto oder einem anderen MQTT-5-Broker verbinden, denn das Fenster wird vom Protokoll selbst ausgehandelt und nicht einseitig konfiguriert.

Checkliste zur Fehlerbehebung

  1. Nachrichten kommen nach dem Reconnect langsam an. Das ist das Fenster bei der Arbeit. Erhöhen Sie es, wenn das Gerät damit zurechtkommt, oder verkleinern Sie den Rückstau mit Message Expiry.
  2. Dem Gerät geht trotzdem der Speicher aus. Prüfen Sie, ob der Großteil des Verkehrs QoS 0 ist; den begrenzt Receive Maximum nicht. Prüfen Sie außerdem die maximale Paketgröße.
  3. Der Publisher stockt. Die Send Quota Ihres Clients ist auf null gefallen, weil das Receive Maximum des Brokers klein ist oder PUBACKs langsam kommen. Protokollieren Sie die CONNACK-Properties.
  4. Trennung mit 0x93. Ein Client hat mehr unbestätigte Nachrichten gesendet als erlaubt; aktualisieren oder korrigieren Sie die Client-Bibliothek.
  5. Die Einstellung wirkt nicht. Sie verbinden sich mit MQTT 3.1.1. Receive Maximum gibt es nur in MQTT 5.

Wie sich gepufferte Nachrichten überhaupt erst anstauen, lesen Sie unter wie MQTT Nachrichten für Offline-Clients puffert. Neu beim Protokoll? Beginnen Sie mit dem MQTT-Tutorial.

Flusskontrolle mit ConnectMQ abstimmen

ConnectMQ betreibt MQTT 3.1.1 und 5.0 über TCP, TLS, WebSocket und sicheren WebSocket, sodass MQTT-5-Properties wie Receive Maximum mit jedem Client funktionieren. Tarifabhängige Kontingente und Flood-Schutz halten einen gemeinsam genutzten MQTT-Broker in der Cloud stabil, während Receive Maximum Ihre einzelnen Geräte schützt. Erstellen Sie einen kostenlosen Serverless-Broker, ohne Kreditkarte, verbinden Sie sich mit YOUR_USERNAME, YOUR_PASSWORD und YOUR_CLIENT_ID und nutzen Sie den MQTT-Client im Browser des Portals, um Testwellen auf Ihre Geräte abzufeuern. Für Produktionsflotten nimmt Ihnen ein verwalteter MQTT-Broker den Broker-Betrieb vollständig ab.

Häufig gestellte Fragen

Was ist der Standardwert von MQTT Receive Maximum?

Wird die Property nicht gesendet, beträgt das Receive Maximum 65.535, was praktisch keinem Limit entspricht. Clients müssen explizit einen kleineren Wert setzen, um Flusskontrolle zu erhalten.

Begrenzt Receive Maximum QoS-0-Nachrichten?

Nein. Es zählt nur QoS-1- und QoS-2-PUBLISH-Pakete, die noch nicht bestätigt wurden. QoS-0-Nachrichten sind in diesem Sinne nie „in flight“.

Gibt es Receive Maximum in MQTT 3.1.1?

Nein. Es ist eine MQTT-5-Property. Clients mit MQTT 3.1.1 verlassen sich auf bibliotheksspezifische In-flight-Einstellungen, die dem Broker nicht mitgeteilt werden.

Was bedeutet der Reason Code 0x93?

Er bedeutet Receive Maximum exceeded: Der Sender hatte mehr unbestätigte QoS-1- oder QoS-2-Nachrichten unterwegs, als der Empfänger erlaubt hat, deshalb hat der Empfänger die Verbindung geschlossen.

Verwandte Artikel

Wer hat MQTT erfunden? Die Geschichte von Ölpipelines bis zum IoT

MQTT wurde 1999 von Andy Stanford-Clark (IBM) und Arlen Nipper (Arcom) erfunden, um Ölpipelines per Satellit zu überwachen. Verfolgen Sie den Weg zu Open Source, OASIS, ISO und den heutigen verwalteten MQTT-Brokern in der Cloud.

8 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.