Freigeben über


Zustandsspeicherprotokoll

Der Zustandsspeicher ist ein verteiltes Speichersystem im Azure IoT Einsatz-Cluster. Der Zustandsspeicher bietet die gleichen Hochverfügbarkeitsgarantien wie MQTT-Nachrichten im MQTT-Broker. Gemäß den MQTT5-/RPC-Protokollrichtlinien müssen Clients MQTT5 verwenden, um mit dem Zustandsspeicher zu interagieren. Dieser Artikel enthält Protokollleitlinien für Entwickler, die ihre eigenen Zustandsspeicherclients implementieren müssen.

Übersicht

Der Zustandsspeicher unterstützt die folgenden Befehle:

  • SET<keyName><keyValue><setOptions>
  • GET<keyName>
  • DEL<keyName>
  • VDEL<keyName><keyValue> ## Löscht ein angegebenes <keyName>-Element nur dann, wenn sein Wert <keyValue> lautet.

Das Protokoll verwendet das folgende Anforderungs-/Antwortmodell:

  • Anforderung: Clients veröffentlichen eine Anforderung in einem gut definierten Systemthema für den Zustandsspeicher. Um die Anforderung zu veröffentlichen, verwenden Clients die erforderlichen Eigenschaften und Nutzlasten, die in den folgenden Abschnitten beschrieben sind.
  • Response: Der Zustandsspeicher verarbeitet die Anforderung asynchron und antwortet auf das Antwortthema, das der Client ursprünglich bereitgestellt hat.

Das folgende Diagramm zeigt die grundlegende Ansicht von Anforderung und Antwort:

Diagramm: Grundlegender Anforderungs- und Antwortprozess für Zustandsspeicher

Zustandsspeicher-Systemthema, QoS und erforderliche MQTT5-Eigenschaften

Für die Kommunikation mit dem Zustandsspeicher müssen Clients die folgenden Anforderungen erfüllen:

  • Verwenden von MQTT5. Weitere Informationen finden Sie in der MQTT 5-Spezifikation.
  • Verwenden von QoS 1 (Servicequalitätsniveau 1). QoS 1 ist in der MQTT 5-Spezifikation beschrieben.
  • Eine Uhr, die maximal eine Minute von der Uhr von MQTT Vermittler abweicht

Um mit dem Zustandsspeicher zu kommunizieren, müssen Clients Anforderungen für das Systemthema statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke veröffentlichen (PUBLISH). Da der Zustandsspeicher Teil von Azure IoT Einsatz ist, führt er beim Start einen impliziten SUBSCRIBE-Vorgang für dieses Thema aus.

Zum Erstellen einer Anforderung sind die folgenden MQTT5-Eigenschaften erforderlich. Wenn diese Eigenschaften nicht vorhanden sind oder die Anforderung nicht vom Typ QoS 1 ist, schlägt die Anforderung fehl.

  • Antwortthema: Der Zustandsspeicher antwortet auf die ursprüngliche Anforderung mit diesem Wert. Als bewährte Methode formatieren Sie das Antwortthema wie folgt: clients/{clientId}/services/statestore/_any_/command/invoke/response. Das Festlegen des Antwortthemas auf statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke oder einen Wert, der mit clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8 beginnt, ist für eine Zustandsspeicheranforderung nicht zulässig. Der Zustandsspeicher trennt MQTT-Clients (Message Queue Telemetry Transport), die ein ungültiges Antwortthema verwenden.
  • Korrelationsdaten: Wenn der Zustandsspeicher eine Antwort sendet, enthält sie die Korrelationsdaten der ursprünglichen Anforderung.

Das folgende Diagramm zeigt eine erweiterte Ansicht von Anforderung und Antwort:

Diagramm: Erweiterter Anforderungs- und Antwortprozess für Zustandsspeicher

Unterstützte Befehle

Die Befehle SET, GET und DEL verhalten sich wie erwartet.

Die Werte, die vom SET-Befehl festgelegt und vom GET-Befehl abgerufen werden, sind beliebige Binärdaten. Die Größe der Werte ist nur durch die maximale MQTT-Nutzlastgröße sowie die Ressourcenbeschränkungen von MQTT-Broker und des Clients begrenzt.

SET-Optionen

Der Befehl SET bietet neben den grundlegenden Flags keyValue und keyName weitere optionale Flags:

  • NX. Ermöglicht das Festlegen des Schlüssels nur, wenn er noch nicht vorhanden ist.
  • NEX <value>. Ermöglicht das Festlegen des Schlüssels nur, wenn der Schlüssel nicht vorhanden ist oder der Wert des Schlüssels bereits auf <Wert> festgelegt ist. Das NEX-Flag wird in der Regel für einen Client verwendet, der den Ablauf (PX) für einen Schlüssel verlängert.
  • PX. Gibt an, wie lange der Schlüssel beibehalten werden soll, bevor er abläuft (in Millisekunden).

VDEL-Optionen

Der Befehl VDEL ist ein Sonderfall des Befehls DEL. DEL löscht den angegebenen keyName-Wert bedingungslos. VDEL erfordert ein weiteres Argument namens keyValue. VDEL löscht das angegebene keyName-Element nur, wenn es denselben keyValue-Wert hat.

Nutzlastformat

Das PUBLISH-Nutzlastformat des Zustandsspeichers ist von RESP3 inspiriert. Dabei handelt es sich um das zugrunde liegende Protokoll, das Redis verwendet. RESP3 codiert sowohl das Verb, z. B. SET oder GET, als auch die Parameter, etwa keyName und keyValue.

Groß- und Kleinschreibung

Der Client muss sowohl die Verben als auch die Optionen im Großbuchstaben senden.

Anforderungsformat

Anforderungen werden wie im folgenden Beispiel formatiert. Gemäß RESP3 stellt * die Anzahl der Elemente in einem Array dar. Das Zeichen $ ist die Anzahl der Zeichen in der folgenden Zeile, mit Ausnahme des nachstehenden CRLF.

Die unterstützten Befehle im RESP3-Format sind GET, SET, DEL und VDEL.

*{NUMBER-OF-ARGUMENTS}<CR><LF>
${LENGTH-OF-NEXT-LINE}<CR><LF>
{COMMAND-NAME}<CR><LF>
${LENGTH-OF-NEXT-LINE}<CR><LF> // This is always the keyName with the current supported verbs.
{KEY-NAME}<CR><LF>
// Next lines included only if command has additional arguments
${LENGTH-OF-NEXT-LINE}<CR><LF> // This is always the keyValue for set
{KEY-VALUE}<CR><LF>

Die folgende Beispielausgabe zeigt RESP3-Nutzlasten des Zustandsspeichers:

*3<CR><LF>$3<CR><LF>set<CR><LF>$7<CR><LF>SETKEY2<CR><LF>$6<CR><LF>VALUE5<CR><LF>
*2<CR><LF>$3<CR><LF>get<CR><LF>$7<CR><LF>SETKEY2<CR><LF>
*2<CR><LF>$3<CR><LF>del<CR><LF>$7<CR><LF>SETKEY2<CR><LF>
*3<CR><LF>$4<CR><LF>vdel<CR><LF>$7<CR><LF>SETKEY2<CR><LF>$3<CR><LF>ABC<CR><LF>

Hinweis

SET erfordert zusätzliche MQTT5-Eigenschaften, wie im Abschnitt Versionsverwaltung und hybride logische Uhren erläutert.

Antwortformat

Wenn der Zustandsspeicher eine ungültige RESP3-Nutzlast erkennt, wird weiterhin eine Antwort auf das Antwortthema (Response Topic) der anfordernden Person zurückgegeben. Beispiele für ungültige Nutzlasten sind ein ungültiger Befehl, ein unzulässiges RESP3-Protokoll oder ein Ganzzahlüberlauf. Eine ungültige Nutzlast beginnt mit der Zeichenfolge -ERR und enthält weitere Details.

Hinweis

Eine Anforderung vom Typ GET, DEL oder VDEL für einen nicht vorhandenen Schlüssel wird nicht als Fehler betrachtet.

Wenn ein Client eine ungültige Nutzlast sendet, sendet der Zustandsspeicher eine Nutzlast wie im folgenden Beispiel:

-ERR syntax error

Antwort von SET

Wenn eine SET-Anforderung erfolgreich ist, gibt der Zustandsspeicher die folgende Nutzlast zurück:

+OK<CR><LF>

Wenn eine SET-Anforderung fehlschlägt, weil eine in den NX- oder NEX-Set-Optionen angegebene Bedingungsprüfung bedeutet, dass der Schlüssel nicht festgelegt werden kann, gibt der Zustandsspeicher die folgende Nutzlast zurück:

-1<CR><LF>

Antwort von GET

Wenn eine GET-Anforderung für einen nicht vorhandenen Schlüssel gesendet wird, gibt der Zustandsspeicher die folgende Nutzlast zurück:

$-1<CR><LF>

Wenn der Schlüssel gefunden wird, gibt der Zustandsspeicher den Wert im folgenden Format zurück:

${NumberOfBytes}<CR><LF>
{KEY-VALUE}

Die Ausgabe des Zustandsspeichers, die den Wert 1234 zurückgibt, sieht wie im folgenden Beispiel aus:

$4<CR><LF>1234<CR><LF>

DEL- und VDEL-Antwort

Der Zustandsspeicher gibt die Anzahl der Werte zurück, die er bei einer Löschanforderung löscht. Derzeit kann der Zustandsspeicher nur jeweils einen Wert löschen.

:{NumberOfDeletes}<CR><LF> // Will be 1 on successful delete or 0 if the keyName is not present

Die folgende Ausgabe ist ein Beispiel für einen erfolgreichen DEL-Befehl:

:1<CR><LF>

Wenn eine VDEL-Anforderung fehlschlägt, weil der angegebene Wert nicht mit dem Wert übereinstimmt, der dem Schlüssel zugeordnet ist, gibt der Zustandsspeicher die folgende Nutzlast zurück:

-1<CR><LF>

-ERR-Antworten

Es folgt die aktuelle Liste der Fehlerzeichenfolgen. Ihre Clientanwendung sollte Zeichenfolgen mit dem Inhalt unbekannter Fehler behandeln, um Updates für den Zustandsspeicher zu unterstützen.

Vom Zustandsspeicher zurückgegebene Fehlerzeichenfolge Erklärung
Der Anforderungszeitstempel liegt zu weit in der Zukunft. Stellen Sie sicher, dass die Systemuhren von Client und Broker synchronisiert sind. Unerwarteter Anforderungszeitstempel, der dadurch verursacht wird, dass Zustandsspeicher und die Systemuhren der Clients nicht synchronisiert sind.
Für diese Anforderung ist ein Umgrenzungstoken erforderlich. Der Fehler tritt auf, wenn ein Schlüssel mit einem Umgrenzungstoken markiert ist, der Client das Umgrenzungstoken jedoch nicht angibt.
Der Anforderungszeitstempel des Umgrenzungstokens liegt zu weit in der Zukunft. Stellen Sie sicher, dass die Systemuhren von Client und Broker synchronisiert sind Unerwarteter angeforderter Umgrenzungstoken-Zeitstempel, der dadurch verursacht wird, dass Zustandsspeicher und Systemuhren der Clients nicht synchronisiert sind.
Das Anforderungsumgrenzungstoken hat eine niedrigere Version als das Umgrenzungstoken, das die Ressource schützt Die Version des Anforderungsumgrenzungstokens ist falsch. Weitere Informationen finden Sie unter [Versionsverwaltung und hybride logische Uhren]. (#versioning-and-hybrid-logical-clocks)
Das Kontingent wurde überschritten. Der Zustandsspeicher verfügt über ein Kontingent für die Anzahl von Schlüsseln, die er speichern kann, das auf dem Speicherprofil des angegebenen MQTT-Brokers basiert.
Syntaxfehler Die gesendete Nutzlast entspricht nicht der Definition des Zustandsspeichers.
Nicht autorisiert Autorisierungsfehler
Unbekannter Befehl Der Befehl wird nicht erkannt.
Falsche Anzahl von Argumenten Falsche Anzahl erwarteter Argumente
Zeitstempel fehlt Wenn Clients einen SET-Befehl ausführen, müssen sie die MQTT5-Benutzereigenschaft __ts als HLC festlegen, die ihren Zeitstempel darstellt.
nicht wohlgeformter Zeitstempel Der Zeitstempel in __ts oder das Umgrenzungstoken ist nicht zulässig.
Die Schlüssellänge ist null. Schlüssel können im Zustandsspeicher nicht die Länge null haben.

Versionsverwaltung und hybride logische Uhren

In diesem Abschnitt wird beschrieben, wie der Zustandsspeicher die Versionsverwaltung behandelt.

Versionen als hybride logische Uhren

Der Zustandsspeicher verwaltet eine Version für jeden gespeicherten Wert. Der Zustandsspeicher könnte einen monoton ansteigenden Zähler verwenden, um Versionen zu verwalten. Stattdessen verwendet der Zustandsspeicher eine hybride logische Uhr (Hybride Logical Clock, HLC), um Versionen darzustellen. Weitere Informationen finden Sie in den Artikeln zum ursprünglichen Entwurf von HLCs und zur Absicht hinter HLCs.

Der Zustandsspeicher verwendet das folgende Format, um HLCs zu definieren:

{wallClock}:{counter}:{node-Id}

wallClock ist die Anzahl von Millisekunden seit der Unix-Epoche. counter und node-Id funktionieren im Allgemeinen als HLCs.

Wenn Clients einen SET-Vorgang durchführen, müssen sie die MQTT5-Benutzereigenschaft __ts basierend auf der aktuellen Uhrzeit des Clients als HLC-Wert (Hybrid Logical Clock) festlegen. Der Zustandsspeicher gibt die Version des Werts in der Antwortnachricht zurück. Die Antwort wird ebenfalls als HLC angegeben und verwendet auch die MQTT5-Benutzereigenschaft __ts. Die zurückgegebene HLC ist immer größer als die HLC der ursprünglichen Anforderung.

Beispiel für das Festlegen und Abrufen der Version eines Werts

In diesem Abschnitt wird ein Beispiel für das Festlegen und Abrufen der Version für einen Wert gezeigt.

Ein Client legt keyName=value fest. Die Clientuhr zeigt Folgendes: 3. Oktober, 23:07:05 Uhr GMT. Der Uhrwert ist 1696374425000 Millisekunden seit der Unix-Epoche. Gehen wir davon aus, dass die Systemuhr des Zustandsspeichers mit der Uhr des Clientsystems identisch ist. Der Client führt den Befehl SET wie zuvor beschrieben aus.

Das folgende Diagramm veranschaulicht den Befehl SET:

Diagramm: Zustandsspeicherbefehl zum Festlegen der Version für einen Wert

Die __ts-Eigenschaft (Zeitstempel) für den anfänglichen Satz enthält 1696374425000 für die Gesamtbetrachtungszeit des Clients, den Zähler 0 und die Knoten-ID CLIENT. Bei der Antwort enthält die __ts-Eigenschaft, die der Zustandsspeicher zurückgibt, wallClock, den um eins erhöhten Zähler und die Knoten-ID StateStore. Basierend auf der Funktionsweise von HLC-Aktualisierungen kann der Zustandsspeicher einen höheren wallClock-Wert zurückgeben, wenn seine Uhr vorgeht.

Diese Version wird auch für erfolgreiche Anforderungen vom Typ GET, DEL und VDEL zurückgegeben. Bei diesen Anforderungen gibt der Client keinen Zeitstempel (__ts) an.

Das folgende Diagramm veranschaulicht den Befehl GET:

Diagramm: Abrufen der Version eines Werts durch den Zustandsspeicher

Hinweis

Der Zeitstempel __ts, den dieser Zustandsspeicher zurückgibt, ist identisch mit dem Wert, den er für die ursprüngliche SET-Anforderung zurückgegeben hat.

Wenn ein bestimmter Schlüssel später mit einem neuen SET-Wert aktualisiert wird, ist der Vorgang ähnlich. Der Client muss den Zeitstempel (__ts) der Anforderung basierend auf der aktuellen Uhr festlegen. Der Zustandsspeicher aktualisiert die Version des Werts und gibt __ts zurück. Dabei werden die HLC-Aktualisierungsregeln eingehalten.

Uhrabweichungen

Der Zustandsspeicher lehnt einen __ts-Wert (und auch __ft) ab, der mehr als eine Minute vor der lokalen Uhr des Zustandsspeichers liegt.

Der Zustandsspeicher akzeptiert einen __ts-Wert, der hinter der lokalen Uhr des Zustandsspeichers liegt. Wie im HLC-Algorithmus angegeben, legt der Zustandsspeicher die Version des Schlüssels auf seine lokale Uhr fest, da sie größer ist.

Sperr- und Fencingtoken

In diesem Abschnitt werden der Zweck und die Verwendung von Sperr- und Fencingtoken beschrieben.

Hintergrund

Angenommen, es gibt zwei oder mehr MQTT-Clients, die den Zustandsspeicher verwenden. Beide Clients möchten in einen bestimmten Schlüssel schreiben. Die Zustandsspeicherclients benötigen einen Mechanismus zum Sperren des Schlüssels, sodass jeweils nur ein Client einen bestimmten Schlüssel ändern kann.

Ein Beispiel für dieses Szenario tritt in aktiven Systemen und Standbysystemen auf. Es können zwei Clients vorhanden sein, die beide denselben Vorgang ausführen, und der Vorgang kann denselben Satz von Zustandsspeicherschlüsseln enthalten. Zu einem bestimmten Zeitpunkt ist einer der Clients aktiv und der andere im Standby, damit er sofort übernehmen kann, wenn das aktive System hängt oder abstürzt. Im Idealfall sollte nur ein Client zu einem bestimmten Zeitpunkt in den Zustandsspeicher schreiben. In verteilten Systemen ist es jedoch möglich, dass sich beide Clients möglicherweise so verhalten, als ob sie aktiv wären, und gleichzeitig versuchen, in dieselben Schlüssel zu schreiben. Dieses Szenario generiert eine Racebedingung.

Der Zustandsspeicher stellt Mechanismen bereit, um diese Racebedingung mithilfe von Fencingtoken zu verhindern. Weitere Informationen zu Fencingtoken und der Klasse der Racebedingungen, gegen die sie schützen sollen, finden Sie in diesem Artikel.

Abrufen eines Fencingtokens

Bei diesem Beispiel wird davon ausgegangen, dass die folgenden Elemente vorhanden sind:

  • Client1 und Client2. Diese Clients sind Zustandsspeicherclients, die als Aktiv-Standby-Paar fungieren.
  • LockName. Der Name eines Schlüssels im Zustandsspeicher, der als Sperre fungiert.
  • ProtectedKey. Der Schlüssel, der vor mehreren Schreibvorgängen geschützt werden muss.

In einem ersten Schritt versuchen die Clients, eine Sperre zu erhalten. Sie erhalten eine Sperre, indem sie einen Vorgang vom Typ SET LockName {CLIENT-NAME} NEX PX {TIMEOUT-IN-MILLISECONDS} ausführen. Unter Set-Optionen haben Sie erfahren, dass das Flag NEX bedeutet, dass SET nur erfolgreich ist, wenn eine der folgenden Bedingungen erfüllt ist:

  • Der Schlüssel war leer.
  • Der Wert des Schlüssels ist bereits auf <Wert> festgelegt, und PX gibt das Timeout in Millisekunden an.

Gehen wir davon aus, dass Client1 zuerst eine Anforderung vom Typ SET LockName Client1 NEX PX 10000 sendet. Durch diese Anforderung wird der Besitz von LockName für 10.000 Millisekunden gewährt. Wenn Client2 eine SET LockName Client2 NEX ...-Anforderung versucht, während Client1 die Sperre besitzt, bedeutet das Flag NEX, dass die Anforderung Client2 fehlschlägt. Client1 muss diese Sperre erneuern, indem derselbe SET-Befehl gesendet wird, der zum Abrufen der Sperre verwendet wurde, wenn sich die Sperre weiterhin im Besitz von Client1 befinden soll.

Hinweis

SET NX entspricht konzeptionell AcquireLock().

Verwenden der Fencingtoken für SET-Anforderungen

Wenn Client1 erfolgreich einen SET-Vorgang (AquireLock) für LockName durchführt, gibt der Zustandsspeicher die Version von LockName als hybride logische Uhr (HLC) in der MQTT5-Benutzereigenschaft __ts zurück.

Wenn ein Client eine SET-Anforderung ausführt, kann er optional die MQTT5-Benutzereigenschaft __ft einschließen, die ein „Fencingtoken“ darstellt. __ft wird als HLC dargestellt. Das Fencingtoken, das einem bestimmten Schlüssel-Wert-Paar zugeordnet ist, stellt die Sperrbesitzprüfung bereit. Das Fencingtoken kann aus einer beliebigen Quelle stammen. Für dieses Szenario sollte es aus der Version von LockName stammen.

Das folgende Diagramm zeigt den Prozess für Client1, der eine SET-Anforderung für LockName ausführt:

Diagramm: Client, der eine SET-Anforderung für die LockName-Eigenschaft ausführt

Als Nächstes verwendet Client1 die Eigenschaft __ts (Property=1696374425000:1:StateStore) unverändert als Grundlage der __ft-Eigenschaft in der Anforderung zum Ändern von ProtectedKey. Wie bei allen SET-Anforderungen muss der Client die __ts-Eigenschaft von ProtectedKey festlegen.

Das folgende Diagramm zeigt den Prozess für Client1, der eine SET-Anforderung für ProtectedKey ausführt:

Diagramm: Client, der eine SET-Anforderung für die ProtectedKey-Eigenschaft ausführt

Wenn die Anforderung erfolgreich ist, erfordert ProtectedKey ab diesem Zeitpunkt ein Fencingtoken, das dem in der SET-Anforderung angegebenen Token entspricht oder größer ist.

Fencingtokenalgorithmus

Der Zustandsspeicher akzeptiert eine HLC für den Zeitstempel (__ts) eines Schlüssel-Wert-Paars, wenn sich der Wert innerhalb der maximalen Uhrabweichung befindet. Dasselbe gilt jedoch nicht für Fencingtoken.

Der Zustandsspeicheralgorithmus für Fencingtoken lautet wie folgt:

  • Wenn einem Schlüssel-Wert-Paar kein Fencingtoken zugeordnet ist und eine SET-Anforderung __ft festlegt, speichert der Zustandsspeicher das zugeordnete Fencingtoken (__ft) mit dem Schlüssel-Wert-Paar.
  • Wenn einem Schlüssel-Wert-Paar ein Fencingtoken zugeordnet ist, gilt Folgendes:
    • Wenn eine SET-Anforderung __ft nicht angegeben hat, wird die Anforderung abgelehnt.
    • Wenn eine SET-Anforderung ein __ft mit einem älteren HLC-Wert als das dem Schlüssel-Wert-Paar zugeordnete Fencingtoken angegeben hat, wird die Anforderung abgelehnt.
    • Wenn eine SET-Anforderung ein __ft angibt, das den gleichen oder einen neueren HLC-Wert hat als das mit dem Schlüssel-Wert-Paar verknüpfte Fencingtoken, wird die Anforderung akzeptiert. Der Zustandsspeicher aktualisiert das Fencingtoken des Schlüssel-Wert-Paares auf das in der Anforderung festgelegte Token, sofern dies neuer ist.

Nachdem ein Schlüssel mit einem Fencingtoken markiert wurde, muss bei DEL- und VDEL-Anforderungen auch die Eigenschaft __ft eingeschlossen werden, damit eine Anforderung erfolgreich ist. Der Algorithmus ist identisch mit dem vorherigen, mit der Ausnahme, dass das Fencingtoken nicht gespeichert wird, da der Schlüssel gelöscht wird.

Clientverhalten

Diese Sperrmechanismen setzen normal funktionierende Clients voraus. Im vorherigen Beispiel konnte Client2 mit Fehlverhalten LockName nicht besitzen und dennoch erfolgreich eine SET ProtectedKey-Anforderung ausführen, indem ein Fencingtoken ausgewählt wurde, das neuer als das ProtectedKey-Token ist. Der Zustandsspeicher weiß nicht, dass LockName und ProtectedKey über eine Beziehung verfügen. Daher führt der Zustandsspeicher keine Überprüfung durch, dass Client2 den Wert tatsächlich besitzt.

Es ist nicht erwünscht, dass Clients Schlüssel schreiben können, für die sie eigentlich nicht die Sperre besitzen. Sie können vor einem solchen Clientfehlverhalten schützen, indem Sie Clients ordnungsgemäß implementieren und Authentifizierung verwenden, um den Zugriff auf Schlüssel nur auf vertrauenswürdige Clients zu beschränken.

Benachrichtigungen

Clients können sich beim Zustandsspeicher registrieren, um Benachrichtigungen über geänderte Schlüssel zu erhalten. Nehmen wir als Beispiel das Szenario, in dem ein Thermostat den Zustandsspeicherschlüssel {thermostatName}\setPoint verwendet. Andere Zustandsspeicherclients können den Wert dieses Schlüssels ändern, um den Sollwert (setPoint) des Thermostats zu ändern. Anstatt Änderungen abzurufen, kann sich der Thermostat beim Zustandsspeicher registrieren, um Nachrichten zu empfangen, wenn {thermostatName}\setPoint geändert wird.

KEYNOTIFY-Anforderungsnachrichten

Zustandsspeicherclients senden eine KEYNOTIFY-Nachricht an den Zustandsspeicher, um anzufordern, dass er einen bestimmten keyName auf Änderungen überwacht. Wie bei allen Zustandsspeicheranforderungen veröffentlichen (PUBLISH) Clients eine QoS1-Nachricht mit dieser Nachricht über MQTT5 im Zustandsspeicher-Systemthema statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke.

Die Anforderungsnutzdaten weisen das folgende Format auf:

KEYNOTIFY<CR><LF>
{keyName}<CR><LF>
{optionalFields}<CR><LF>

Hierbei gilt:

  • KEYNOTIFY ist ein Zeichenfolgenliteral, das den Befehl angibt.
  • {keyName} ist der Schlüsselname, für den auf Benachrichtigungen gelauscht werden soll. Platzhalter werden derzeit nicht unterstützt.
  • {optionalFields}: Folgende optionale Feldwerte werden derzeit unterstützt:
    • {STOP}: Wenn eine Benachrichtigung mit den in dieser Anforderung angegebenen keyName- und clientId-Werten vorhanden ist, wird sie vom Zustandsspeicher entfernt.

Die folgende Beispielausgabe zeigt eine KEYNOTIFY-Anforderung zum Überwachen des Schlüssels SOMEKEY:

*2<CR><LF>
$9<CR><LF>
KEYNOTIFY<CR><LF>
$7<CR><LF>
SOMEKEY<CR><LF>

KEYNOTIFY-Antwortnachricht

Wie bei allen RPC-Zustandsspeicheranforderungen (Remote Procedure Call, Remoteprozeduraufruf) gibt der Zustandsspeicher seine Antwort an das Response Topic zurück und verwendet die in der ursprünglichen Anforderung angegebenen Correlation Data-Eigenschaften. Bei KEYNOTIFY gibt eine erfolgreiche Antwort an, dass der Zustandsspeicher die Anforderung verarbeitet hat. Nach der erfolgreichen Verarbeitung der Anforderung überwacht der Zustandsspeicher entweder den Schlüssel für den aktuellen Client, oder er beendet die Überwachung.

Bei erfolgreicher Ausführung ist die Antwort des Zustandsspeichers mit der bei einem erfolgreichen SET-Vorgang identisch.

+OK<CR><LF>

Wenn ein Client eine KEYNOTIFY SOMEKEY STOP-Anforderung sendet, der Zustandsspeicher diesen Schlüssel jedoch nicht überwacht, ist die Antwort des Zustandsspeichers mit der beim Versuch, einen nicht vorhandenen Schlüssel zu löschen, identisch.

:0<CR><LF>

Alle anderen Fehler folgen dem allgemeinen Fehlermeldungsmuster des Zustandsspeichers:

-ERR: <DESCRIPTION OF ERROR><CR><LF>

KEYNOTIFY-Benachrichtigungsthemen und -Lebenszyklus

Wenn ein über KEYNOTIFY überwachter keyName geändert oder gelöscht wird, sendet der Zustandsspeicher eine Benachrichtigung an den Client. Das Thema wird durch Konventionen bestimmt – der Client gibt das Thema während des KEYNOTIFY-Prozesses nicht an.

Das folgende Beispiel zeigt die Definition des Themas. Die clientId ist eine hexadezimal codierte Darstellung in Großbuchstaben der MQTT-ClientId des Clients, der die KEYNOTIFY-Anforderung initiiert hat, und keyName ist eine hexadezimal codierte Darstellung des geänderten Schlüssels. Der Statusspeicher folgt den Base 16-Codierungsregeln von RFC 4648 – Base16-, Base32- und Base64-Datencodierungen für diese Codierung.

clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/{clientId}/command/notify/{keyName}

MQTT-Broker veröffentlicht beispielsweise eine an client-id1 gesendete NOTIFY-Nachricht mit dem geänderten Schlüsselnamen SOMEKEY im Thema:

clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/636C69656E742D696431/command/notify/534F4D454B4559`

Damit keine Nachrichten verloren gehen, sollte ein Client, der Benachrichtigungen verwendet, dieses Thema mit SUBSCRIBE abonnieren und auf den Empfang von SUBACK warten, bevor er KEYNOTIFY-Anforderungen sendet.

Wenn ein Client die Verbindung trennt, muss er das KEYNOTIFY-Benachrichtigungsthema erneut abonnieren und den KEYNOTIFY-Befehl nochmals für alle Schlüssel senden, die weiterhin überwacht werden müssen. Im Gegensatz zu MQTT-Abonnements, die in einer nicht bereinigten Sitzung beibehalten werden können, entfernt der Zustandsspeicher intern alle KEYNOTIFY-Nachrichten, wenn ein bestimmter Client die Verbindung trennt.

Format der KEYNOTIFY-Benachrichtigung

Wenn ein über KEYNOTIFY überwachter Schlüssel geändert wird, veröffentlicht der Zustandsspeicher mit PUBLISH eine Nachricht im folgenden Format im Benachrichtigungsthema für Zustandsspeicherclients, die für die Änderung registriert sind.

NOTIFY<CR><LF>
{operation}<CR><LF>
{optionalFields}<CR><LF>

Die folgenden Details sind in der Nachricht enthalten:

  • NOTIFY ist ein Zeichenfolgenliteral, das als erstes Argument in den Nutzdaten enthalten ist und angibt, dass eine Benachrichtigung eingegangen ist.
  • {operation} ist das Ereignis, das aufgetreten ist. Zurzeit werden folgende Vorgänge unterstützt:
    • SET: Der Wert wurde geändert. Dieser Vorgang kann nur in Folge eines SET-Befehls von einem Zustandsspeicherclient auftreten.
    • DEL: Der Wert wurde gelöscht. Dieser Vorgang kann aufgrund eines DEL- oder VDEL-Befehls von einem Zustandsspeicherclient auftreten.
  • optionalFields
    • VALUE und {MODIFIED-VALUE}. VALUE ist ein Zeichenfolgenliteral, das angibt, dass das nächste Feld, {MODIFIED-VALUE}, den Wert enthält, in den der Schlüssel geändert wurde. Dieser Wert wird nur als Antwort auf Schlüssel gesendet, die aufgrund von SET geändert werden.

Die folgende Beispielausgabe zeigt eine Benachrichtigung, die gesendet wird, wenn der Schlüssel SOMEKEY in den Wert abc geändert wird, wobei der VALUE enthalten ist, weil in der ursprünglichen Anforderung die GET-Option angegeben war:

*4<CR><LF>
$6<CR><LF>
NOTIFY<CR><LF>
$3<CR><LF>
SET<CR><LF>
$5<CR><LF>
VALUE<CR><LF>
$3<CR><LF>
abc<CR><LF>

Die KEYNOTIFY-Benachrichtigung enthält den Zeitstempel des Werts, wann ein Client über eine SET-Anforderung benachrichtigt wird (Wert aktualisiert) oder wenn ein Client über eine DEL- oder VDEL-Anforderung benachrichtigt wird (Wert gelöscht). Der Zeitstempel ist teil der MQTT v5 User Property __ts der Nachricht. Weitere Informationen finden Sie im Abschnitt Versionen als Hybrid Logical Clocks.