Nachrichtenübertragungen, Sperren und Abgleich

Die zentrale Funktion eines Nachrichtenbrokers wie z.B. Service Bus besteht darin, Nachrichten in einer Warteschlange oder einem Thema anzunehmen und zum späteren Abruf verfügbar zu halten. Senden ist der allgemein gebräuchliche Begriff für die Übertragung einer Nachricht in den Nachrichtenbroker. Empfangen ist der allgemein gebräuchliche Begriff für die Übertragung einer Nachricht an einen abrufenden Client.

Wenn ein Client eine Nachricht sendet, möchte er normalerweise wissen, ob die Nachricht ordnungsgemäß an den Broker übertragen und vom Broker akzeptiert wird oder ob ein Fehler aufgetreten ist. Diese positive oder negative Bestätigung gleicht die Kenntnis des Clients und des Brokers über den Übertragungsstatus der Nachricht ab. Daher wird sie als Abgleich bezeichnet.

Wenn der Broker eine Nachricht an einen Client überträgt, möchten der Broker und der Client ebenso darüber übereinkommen, ob die Nachricht erfolgreich verarbeitet wird und daher entfernt werden kann, oder ob bei der Übertragung oder Verarbeitung der Nachricht ein Fehler aufgetreten ist und die Nachricht daher möglicherweise erneut übertragen werden muss.

Abgleichen von Sendevorgängen

Bei Verwendung aller unterstützten Service Bus-API-Clients werden Sendevorgänge in Service Bus immer explizit abgeglichen. Das bedeutet, dass der API-Vorgang auf den Empfang eines Annahmeergebnisses von Service Bus wartet und dann den Sendevorgang abschließt.

Wenn die Nachricht von Service Bus abgelehnt wird, enthält die Ablehnung einen Fehlerindikator sowie Text mit einer Nachverfolgungs-ID (tracking-id). Die Ablehnung enthält auch Informationen darüber, ob der Vorgang mit Aussicht auf Erfolg wiederholt werden kann. Im Client werden diese Informationen in eine Ausnahme umgewandelt und für den Aufrufer des Sendevorgangs ausgelöst. Wenn die Nachricht akzeptiert wird, wird der Vorgang automatisch abgeschlossen.

AMQP (Advanced Messaging Queuing Protocol) ist das einzige Protokoll, das für .NET Standard-, Java-, JavaScript-, Python- und Go-Clients unterstützt wird. Für .NET Framework-Clients können Sie SBMP (Service Bus Messaging Protocol) oder AMQP verwenden. Wenn Sie das AMQP-Protokoll verwenden, erfolgen Nachrichtenübertragungen und -abrechnungen in einer Pipeline und asynchron. Es wird empfohlen, die API-Varianten des asynchronen Programmiermodells zu verwenden.

Am 30. September 2026 werden die Azure Service Bus SDK-Bibliotheken „WindowsAzure.ServiceBus“, „Microsoft.Azure.ServiceBus“ und „com.microsoft.azure.servicebus“ eingestellt, da sie nicht den Azure SDK-Richtlinien entsprechen. Außerdem wird die Unterstützung des SBMP-Protokolls beendet, sodass Sie dieses Protokoll nach dem 30. September 2026 nicht mehr verwenden können. Migrieren Sie vor diesem Datum zu den neuesten Azure SDK-Bibliotheken, die wichtige Sicherheitsupdates und verbesserte Funktionen bieten.

Obwohl die älteren Bibliotheken noch über den 30. September 2026 hinaus verwendet werden können, erhalten sie keinen offiziellen Support und keine Updates mehr von Microsoft. Weitere Informationen finden Sie in der Ankündigung der Supporteinstellung.

Ein Sender kann mehrere Nachrichten in schneller Folge übertragen, ohne darauf warten zu müssen, dass jede Nachricht bestätigt wird, wie dies andernfalls bei Verwendung des SBMP-Protokolls oder mit HTTP 1.1 der Fall wäre. Diese asynchronen Sendevorgänge werden abgeschlossen, wenn die entsprechenden Nachrichten in partitionierten Entitäten angenommen und gespeichert werden oder wenn sich Sendevorgänge an unterschiedliche Entitäten überlappen. Die Abschlüsse können auch außerhalb der ursprünglichen Sendereihenfolge erfolgen.

Die Strategie zur Verarbeitung des Ergebnisses von Sendevorgängen kann direkte und erhebliche Leistungsauswirkungen auf die Anwendung haben. Die Beispiele in diesem Abschnitt sind in C# geschrieben und gelten für Java-Futures, Java-Monos, JavaScript-Zusagen und entsprechende Konzepte in anderen Programmiersprachen.

Wenn die Anwendung eine Burstübertragung von Nachrichten generiert, hier mit einer einfachen Schleife dargestellt, und der Abschluss jedes Sendevorgangs abgewartet werden muss, bevor die nächste Nachricht gesendet werden kann, wird das Senden von 10 Nachrichten bei synchronen wie auch bei asynchronen API-Formen erst nach 10 sequenziellen vollständigen Roundtrips für den Abgleich abgeschlossen.

Bei einer angenommenen Latenzentfernung des Transmission Control-Protokoll(TCP)-Roundtrips von 70 Millisekunden zwischen einem lokalen Standort und Service Bus sowie der Annahme von nur 10 ms für Service Bus zum Akzeptieren und Speichern jeder Nachricht dauert die folgende Schleife mindestens acht Sekunden (ohne Berücksichtigung der Übertragungszeit der Nutzdaten oder der Auswirkungen einer potenziellen Überlastung bei der Weiterleitung):

for (int i = 0; i < 10; i++)
{
    // creating the message omitted for brevity
    await sender.SendMessageAsync(message);
}

Wenn die Anwendung die zehn asynchronen Sendevorgänge in direkter Folge startet und gesondert auf den jeweiligen Abschluss wartet, überschneidet sich die Roundtripzeit für diese zehn Sendevorgänge. Die 10 Nachrichten werden in direkter Folge übertragen und teilen möglicherweise sogar TCP-Frames. Die gesamte Übertragungsdauer hängt dann weitgehend von der netzwerkbezogenen Zeit für die Übertragung der Nachrichten an den Broker ab.

Bei den gleichen Annahmen wie für die vorherige Schleife bleibt die gesamte überlappende Ausführungszeit für die folgende Schleife möglicherweise unter einer Sekunde:

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    tasks.Add(sender.SendMessageAsync(message));
}
await Task.WhenAll(tasks);

Dabei ist unbedingt zu beachten, dass alle asynchronen Programmiermodelle eine Form einer speicherbasierten, verborgenen Arbeitswarteschlange verwenden, die ausstehende Vorgänge enthält. Wenn die Sende-API die Kontrolle zurückgibt, wird die Sendeaufgabe in dieser Arbeitswarteschlange eingereiht, aber die Protokollgeste beginnt erst, wenn die Aufgabe an der Reihe ist, ausgeführt zu werden. Bei Code, der tendenziell eine Burstübertragung von Nachrichten generiert und bei dem Zuverlässigkeit relevant ist, sollte darauf geachtet werden, dass nicht zu viele Nachrichten gleichzeitig aktiv sind, da alle gesendeten Nachrichten Speicher belegen, bis sie übertragen werden.

Semaphore, wie im folgenden Codeausschnitt in C# gezeigt, sind Synchronisierungsobjekte, die eine solche Drosselung auf Anwendungsebene bei Bedarf ermöglichen. Bei dieser Verwendung eines Semaphors können höchstens 10 Nachrichten gleichzeitig aktiv sein. Eine der 10 verfügbaren Semaphorsperren wird vor dem Senden festgelegt und aufgehoben, wenn der Sendevorgang abgeschlossen ist. Der 11. Durchlauf durch die Schleife wartet, bis mindestens einer der vorherigen Sendevorgänge abgeschlossen ist, und macht dann seine Sperre verfügbar:

var semaphore = new SemaphoreSlim(10);

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    await semaphore.WaitAsync();

    tasks.Add(sender.SendMessageAsync(message).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

Anwendungen sollten niemals einen asynchronen „Fire-and-Forget“-Sendevorgang initiieren, ohne das Ergebnis des Vorgangs abzurufen. Andernfalls kann dies dazu führen, dass die interne und nicht sichtbare Taskwarteschlange bis zur Ausschöpfung des Speichers geladen wird und die Anwendung Sendefehler nicht erkennen kann:

for (int i = 0; i < 10; i++)
{
    sender.SendMessageAsync(message); // DON’T DO THIS
}

Mit einem AMQP-Client auf niedriger Ebene akzeptiert Service Bus auch „vorab abgeglichene“ Übertragungen. Eine vorab abgeglichene Übertragung ist ein Fire-and-Forget-Vorgang, bei dem das Ergebnis (in beiden Fällen) nicht zurück an den Client gesendet wird und die Nachricht nach dem Senden als abgeglichen gilt. Das fehlende Feedback an den Client bedeutet auch, dass keine verwertbaren Daten für die Diagnose verfügbar sind. Das heißt, dass bei diesem Modus keine Unterstützung über den Azure-Support möglich ist.

Abgleichen von Empfangsvorgängen

Für Empfangsvorgänge ermöglichen die Service Bus-API-Clients zwei verschiedene explizite Modi: Receive-and-Delete und Peek-Lock.

ReceiveAndDelete

Im Modus Receive-and-Delete wird der Broker angewiesen, alle an den empfangenden Client gesendeten Nachrichten nach dem Senden als abgeglichen einzustufen. Das bedeutet, dass eine Nachricht als verarbeitet gilt, sobald der Broker sie überträgt. Wenn bei der Nachrichtenübertragung ein Fehler auftritt, geht die Nachricht verloren.

Der Vorteil dieses Modus besteht darin, dass der Empfänger keine weitere Aktion für die Nachricht ausführen muss und auch nicht dadurch verlangsamt wird, dass er auf das Ergebnis des Abgleichs warten muss. Wenn die in den einzelnen Nachrichten enthaltenen Daten einen geringen Wert haben und/oder nur für einen sehr kurzen Zeitraum aussagekräftig sind, ist dieser Modus sinnvoll.

PeekLock

Im Modus Peek-Lock wird der Broker angewiesen, dass der empfangende Client empfangene Nachrichten explizit abgleichen möchte. Die Nachricht wird für den Empfänger zur Verarbeitung verfügbar gemacht und gleichzeitig im Dienst exklusiv gesperrt, sodass andere konkurrierende Empfänger sie nicht sehen können. Die Dauer der Sperre wird anfänglich auf Warteschlangen- oder Abonnementebene definiert und kann von dem Client, der die Sperre besitzt, über den Vorgang RenewMessageLockAsync verlängert werden. Ausführliche Informationen zum Verlängern von Sperren finden Sie in diesem Artikel im Abschnitt Verlängern von Sperren.

Wenn eine Nachricht gesperrt ist, können andere Clients, die Nachrichten von derselben Warteschlange oder demselben Abonnement empfangen, Sperren annehmen und die nächsten verfügbaren Nachrichten abrufen, die nicht aktiv gesperrt sind. Wenn die Sperre für eine Nachricht explizit aufgehoben wird oder abläuft, wird die Nachricht zur erneuten Übertragung ganz oder nahe an den Anfang in der Abrufreihenfolge gesetzt.

Wenn die Nachricht wiederholt von Empfängern freigegeben wird oder diese die Sperre nach einer bestimmten Anzahl von Übertragungen (Anzahl maximaler Zustellungen) ablaufen lassen, wird die Nachricht automatisch aus der Warteschlange oder dem Abonnement entfernt und in der zugeordneten Warteschlange für unzustellbare Nachrichten platziert.

Der empfangende Client initiiert den Abgleich einer empfangenen Nachricht mit einer positiven Bestätigung, wenn er die API Complete für die Nachricht aufruft. Für den Broker bedeutet das, dass die Nachricht erfolgreich verarbeitet wurde. Die Nachricht wird dann aus der Warteschlange oder dem Abonnement entfernt. Der Broker antwortet auf die Abgleichabsicht des Empfängers mit einer Antwort, die angibt, ob der Abgleich ausgeführt werden kann.

Wenn der empfangende Client eine Nachricht nicht verarbeiten kann, die Nachricht jedoch erneut übertragen werden soll, kann er explizit anfordern, dass die Nachricht freigegeben und die Sperre direkt aufgehoben werden soll, indem er die API Abandon für die Nachricht aufruft. Alternativ kann der Client keine Aktion ausführen und die Sperre ablaufen lassen.

Wenn ein empfangender Client eine Nachricht nicht verarbeiten kann und weiß, dass die erneute Übertragung der Nachricht und die Wiederholung des Vorgangs nicht hilft, kann er die Nachricht ablehnen. Die Nachricht wird daraufhin durch Aufrufen der DeadLetter-API für die Nachricht in die Warteschlange für unzustellbare Nachrichten verschoben. Dies ermöglicht auch die Festlegung einer benutzerdefinierten Eigenschaft mit einem Ursachencode, der mit der Nachricht aus der Warteschlange für unzustellbare Nachrichten abgerufen werden kann.

Hinweis

Für eine Warteschlange oder ein Themenabonnement ist nur eine Inschrift mit inaktiven Buchstaben vorhanden, wenn die Warteschlange oder das Abonnement für die Warteschlange oder das Abonnement aktiviert ist.

Ein Sonderfall des Abgleichs ist die Verzögerung, die in einem separaten Artikel beschrieben wird.

Bei den Vorgängen Complete, DeadLetter und RenewLock können aufgrund von Netzwerkproblemen Fehler auftreten, wenn die festgelegte Sperre abgelaufen ist oder andere dienstseitige Bedingungen die Abwicklung verhindern. In einem der letzteren Fälle sendet der Dienst eine negative Bestätigung, die in den API-Clients als Ausnahme angezeigt wird. Wenn die Ursache eine unterbrochene Netzwerkverbindung ist, wird die Sperre gelöscht, da Service Bus die Wiederherstellung von vorhandenen AMQP-Links für eine andere Verbindung nicht unterstützt.

Ist Complete nicht erfolgreich (in der Regel ganz am Ende der Nachrichtenverarbeitung, in einigen Fällen aber auch nach mehreren Minuten der Verarbeitung), kann die empfangende Anwendung entscheiden, ob sie den Status der Arbeit beibehält und die Nachricht ignoriert, wenn sie ein zweites Mal übertragen wird, oder ob sie das Arbeitsergebnis verwirft und den Vorgang bei der erneuten Übertragung der Nachricht wiederholt.

Das typische Verfahren zum Identifizieren von doppelten Nachrichtenübertragungen besteht in der Überprüfung der Nachrichten-ID (message-id), die vom Sender auf einen eindeutigen Wert festgelegt werden kann und sollte, eventuell verbunden mit einem Bezeichner vom sendenden Prozess. Ein Auftragsplaner wird wahrscheinlich die message-id auf den Bezeichner des Auftrags, der einem Worker zugewiesen werden soll, mit dem gegebenen Worker festlegen, und der Worker wird das zweite Vorkommen der Auftragszuweisung ignorieren, sofern der Auftrag bereits abgeschlossen ist.

Wichtig

Beachten Sie unbedingt, dass die Sperre, die PeekLock oder SessionLock für die Nachricht abruft, flüchtig ist und unter den folgenden Bedingungen verloren gehen kann:

  • Dienstupdate
  • Betriebssystemupdate
  • Ändern von Eigenschaften für die Entität (Warteschlange, Thema, Abonnement) während der Sperre.

Wenn die Sperre verloren geht, generiert Azure Service Bus eine MessageLockLostException oder SessionLockLostException, die in der Clientanwendung angezeigt wird. In diesem Fall sollte die standardmäßige Wiederholungslogik des Clients automatisch gestartet werden und den Vorgang wiederholen.

Verlängern von Sperren

Der Standardwert für die Sperrdauer beträgt 1 Minute. Sie können einen anderen Wert für die Sperrdauer auf Warteschlangen- oder Abonnementebene angeben. Der Client, der die Sperre besitzt, kann die Nachrichtensperre mithilfe von Methoden für das Empfängerobjekt verlängern. Stattdessen können Sie das Feature für die automatische Verlängerung von Sperren verwenden und dort den Zeitraum angeben, für den die Sperre verlängert werden soll.

Es ist am besten, die Sperrdauer höher als Ihre normale Verarbeitungszeit festzulegen, damit Sie die Sperre nicht erneuern müssen. Der Maximalwert beträgt 5 Minuten, sodass Sie die Sperre erneuern müssen, wenn sie länger bestehen soll. Eine längere Sperrdauer als erforderlich hat auch einige Auswirkungen. Wenn ihr Client beispielsweise nicht mehr funktioniert, wird die Nachricht erst wieder verfügbar, nachdem die Sperrdauer abgelaufen ist.

Nächste Schritte