Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gruppieren Sie verwandte Nachrichten nach einem Kategorieschlüssel, und verarbeiten Sie jede Gruppe sequenziell, jeweils eine Nachricht, während sie verschiedene Gruppen parallel verarbeiten.
Dieses Muster löst den Konflikt zwischen der Aufrechterhaltung der First-In-First-Out-Korrektheit (FIFO) innerhalb jeder logischen Gruppe und der horizontalen Skalierung der gleichzeitigen Verarbeitung über Gruppen hinweg. Das Design stellt sicher, dass Beschränkungen bei der Reihenfolge nicht zu einem systemweiten Engpass werden.
Kontext und Problem
Anwendungen müssen häufig zusammenhängende Nachrichten in der Reihenfolge ihres Eingangs verarbeiten und gleichzeitig weiter skalieren, um steigende Last zu bewältigen. In einer verteilten Architektur ist diese Anforderung schwer zu erfüllen, da Worker Nachrichten unabhängig aus einer gemeinsamen Warteschlange abrufen. Wenn mehrere Worker um Nachrichten konkurrieren, wie beim Muster „Konkurrierende Consumer“, geht die Reihenfolge verloren.
Erwägen Sie ein Bestellverfolgungssystem, das einen Datenstrom von Vorgängen empfängt, z. B. das Erstellen einer Bestellung, das Hinzufügen einer Transaktion, das Ändern einer früheren Transaktion und das Löschen einer Bestellung. Die Vorgänge jeder Bestellung müssen in FIFO-Reihenfolge verarbeitet werden, da ihr Anwenden in einer anderen Reihenfolge den Zustand der Bestellung beschädigen würde. Die eingehende Warteschlange verschachtelt jedoch Vorgänge über viele Aufträge hinweg. Ein einzelner Verbraucher, der die globale Sortierung erzwingt, wird zu einem Engpass, und mehrere Verbraucher verarbeiten möglicherweise die Vorgänge derselben Bestellung außerhalb der Reihenfolge.
Die naheliegenden Ansätze für dieses Problem scheitern jeweils auf unterschiedliche Weise:
Einzelner Verbraucher. Ein einzelner Consumer behält die Nachrichtenreihenfolge bei, da er jeweils nur eine Nachricht verarbeitet, kann aber nicht skaliert werden, um einen höheren Durchsatz zu bewältigen.
Mehrere konkurrierende Verbraucher. Mehrere Consumer skalieren den Durchsatz, indem sie Nachrichten parallel abrufen, verlieren jedoch die Garantien für die Reihenfolge pro Gruppe. Zwei Mitarbeiter können aufeinanderfolgende Nachrichten für dieselbe Bestellung abrufen und sie gleichzeitig oder in falscher Reihenfolge verarbeiten, wodurch der Bestellstatus korrumpiert wird.
Lösung
Das sequenzielle Konvoy-Muster partitioniert verwandte Nachrichten in Kategorien und verarbeitet jede Kategorie sequenziell, jeweils eine Nachricht, während Kategorien parallel verarbeitet werden.
Das Muster funktioniert, indem jeder Nachricht ein Kategorieschlüssel zugewiesen wird, der die Gruppe identifiziert, zu der sie gehört. Ein Nachrichtenbroker verwendet diesen Schlüssel, um Nachrichten in logische Gruppen zu partitionieren. Innerhalb jeder Gruppe erzwingt der Broker die FIFO-Reihenfolge, sodass ein Consumer, der eine Gruppe sperrt, Nachrichten strikt in der Reihenfolge empfängt, in der sie in die Warteschlange eingereiht wurden. Unterschiedliche Gruppen können von verschiedenen Verbrauchern gleichzeitig verarbeitet werden, sodass das System horizontal über Gruppen skaliert wird, ohne die Reihenfolge innerhalb einer einzelnen Gruppe zu beeinträchtigen.
In Azure stellen Azure Service Bus Nachrichtensitzungen eine integrierte Implementierung dieses Musters bereit.
Das folgende Diagramm zeigt das allgemeine sequenzielle Konvoymuster.
In der Warteschlange können Nachrichten für verschiedene Kategorien abwechselnd angeordnet sein, wie im folgenden Diagramm dargestellt.
Dieses Muster bietet mehrere wichtige Vorteile:
Verarbeitung in geordneter Reihenfolge je Gruppe. Nachrichten innerhalb jeder Kategorie werden strikt nacheinander verarbeitet, was Racebedingungen, Statusmutationen in falscher Reihenfolge und die Notwendigkeit von Problemumgehungen zur Neuordnung verhindert.
Horizontale Skalierung über Gruppen hinweg. Jede Kategorie ist eine unabhängige Einheit der Parallelität. Das Hinzufügen von Verbrauchern erhöht den Durchsatz proportional zur Anzahl der aktiven Kategorien, ohne die Sortiergarantien zu unterbrechen.
Hersteller-Verbraucher-Entkoppelung. Producer reihen Nachrichten in die Warteschlange ein, ohne zu wissen, welcher Consumer sie wann verarbeiten wird. Verbraucher sind unabhängig skalierbar und austauschbar.
Probleme und Überlegungen
Beachten Sie die folgenden Punkte bei Ihrer Entscheidung, wie dieses Muster implementiert werden soll:
Kategorie und Maßeinheit. Bestimmen Sie, welche Eigenschaft Ihrer eingehenden Nachrichten Sie zur horizontalen Skalierung nutzen können. Der Kategorieschlüssel definiert die Parallelitätseinheit: Jeder unterschiedliche Schlüsselwert wird zu einer unabhängig prozessierbaren Gruppe. Im Szenario "Bestellnachverfolgung" ist diese Eigenschaft die Bestell-ID. Die Auswahl eines zu groben Schlüssels (z. B. eine einzige Kunden-ID für alle Aufträge) schränkt die Parallelität ein, während die Auswahl eines zu feinen Schlüssels keinen sinnvollen Vorteil bei der Reihenfolge bietet.
Durchsatzgrenzwerte. Bewerten Sie Ihren Ziel-Nachrichtendurchsatz. Da dieses Muster die sequenzielle Verarbeitung innerhalb jeder Kategorie erzwingt, ist der Durchsatz pro Kategorie an die Zeit gebunden, um eine einzelne Nachricht zu verarbeiten. Optimieren Sie die Verarbeitungszeit pro Nachricht, z. B. mithilfe asynchroner E/A- oder Batchverarbeitung nachgeschalteter Schreibvorgänge, da diese Zeit den maximalen Durchsatz für jede Kategorie direkt bestimmt. Wenn Ihre Gesamtdurchsatzanforderung sehr hoch ist, überlegen Sie, ob eine strenge FIFO-Sortierung für den gesamten Nachrichtenlebenszyklus erforderlich ist. Alternativen umfassen, eine Start- und eine Endnachricht vorzuschreiben, um eine Sequenz einzurahmen, oder Nachrichten innerhalb eines Batch-Fensters nach Zeitstempel zu sortieren und den Batch dann zur parallelen Verarbeitung zu senden.
Servicefunktionen. Überprüfen Sie, ob Ihre Wahl des Nachrichtenbrokers die einmalige Verarbeitung von Nachrichten in einer Warteschlange oder Kategorie einer Warteschlange unterstützt. Nicht alle Messagingdienste bieten Sperrung auf Sitzungsebene oder FIFO-Garantien innerhalb einer Partition. Wenn der Broker diese Funktion nicht nativ unterstützt, muss der Verbraucher eine eigene Koordinationslogik implementieren, die Komplexität und Risiken für die doppelte Verarbeitung, verpasste Nachrichten oder out-of-order-Ausführung hinzufügt. Die Unterstützung von Sitzungen kann auch die Wahl des Messaging-Tarifs oder der SKU einschränken, was sich auf die Kosten auswirkt.
Weiterentwicklungsfähigkeit. Planen Sie, wie Sie dem System neue Kategorien von Nachrichten hinzufügen. Das Muster muss das Wachstum der Kategoriekardinalität berücksichtigen, ohne dass strukturelle Änderungen an den Consumern erforderlich sind. Nehmen wir beispielsweise an, dass das zuvor beschriebene Hauptbuchsystem auf einen einzelnen Kunden zugeschnitten ist. Wenn Sie einen neuen Kunden aufnehmen müssen, sollten Sie in der Lage sein, eine Reihe von Ledger-Prozessoren hinzuzufügen, die die Arbeit anhand der Kunden-ID verteilen, ohne die Warteschlangentopologie neu entwerfen zu müssen.
Zustellung von Nachrichten in falscher Reihenfolge. Nachrichten können aufgrund variabler Netzwerklatenz zwischen dem Producer und dem Broker in falscher Reihenfolge ankommen, bevor die Sitzungsreihenfolge des Brokers wirksam wird. Erwägen Sie die Verwendung von Sequenznummern, um die Reihenfolge innerhalb jeder Kategorie zu überprüfen. Sie können auch ein End-of-Sequence-Flag in die letzte Nachricht einer Transaktion einschließen, damit Verbraucher erkennen können, wann eine Sequenz abgeschlossen ist.
Behandlung von nicht verarbeitbaren Nachrichten. Eine Nachricht, bei der die Verarbeitung innerhalb einer Sitzung wiederholt fehlschlägt, blockiert alle nachfolgenden Nachrichten in dieser Sitzung, da das Muster eine strenge sequenzielle Anordnung erzwingt. Entwerfen Sie eine Strategie zum Erkennen fehlerhafter Nachrichten, etwa durch Nachverfolgen der Anzahl der Zustellversuche, und verschieben Sie sie nach einem festgelegten Schwellenwert für Wiederholungsversuche in eine Dead-Letter-Warteschlange, damit die verbleibenden Nachrichten in der Sitzung weiterverarbeitet werden können.
Verfügbarkeit des Brokers. Der Message-Broker ist eine gemeinsame Abhängigkeit für alle Kategorien. Ihre Verfügbarkeit und Haltbarkeit wirken sich direkt auf die Zuverlässigkeitsgarantien des Musters aus. Bewerten Sie Resilienzfunktionen auf Broker-Ebene, z. B. Verfügbarkeitszonen und geografische Notfallwiederherstellung, anhand der Verfügbarkeitsanforderungen und des Budgets des Workloads, da Konfigurationen mit höherer Dauerhaftigkeit in der Regel die Kosten erhöhen.
Korrektheit des Producer-Schlüssels. Bei diesem Muster wird davon ausgegangen, dass Produzenten den Kategorieschlüssel (Sitzungs-ID) für jede Nachricht richtig festlegen. Wenn ein Produzent einen falschen Schlüssel festlegt, entweder versehentlich oder aufgrund eines Fehlers, leitet die Nachricht an die falsche Sitzung weiter und beschädigt den Status dieser Gruppe. Überprüfen Sie, ob Produzenten Kategorieschlüssel konsistent zuweisen, und erwägen Sie, schlüsselüberprüfungslogik beim Verbraucher hinzuzufügen, wenn die Folge einer falsch umgeleiteten Nachricht schwerwiegend ist.
Betriebskomplexität. Die Überwachung der sitzungsbasierten Verarbeitung verursacht einen höheren betrieblichen Mehraufwand als die standardmäßige Nutzung von Warteschlangen. Betreiber benötigen Transparenz über Sitzungsrückstände (die Anzahl aktiver Sitzungen und die Anzahl der je Sitzung wartenden Nachrichten), um Kategorien zu identifizieren, die ins Hintertreffen geraten. Sitzungen mit unzustellbaren Nachrichten erfordern einen separaten Überwachungs- und Behebungsworkflow, um fehlgeschlagene Nachrichten zu untersuchen, die Grundursache zu beheben und korrigierte Nachrichten wieder in die Sitzung einzuspielen.
Konflikte und Latenz bei Sitzungssperren. Die Sitzungssperre führt zu Latenzaufwand, da jeder Verbraucher vor der Verarbeitung von Nachrichten eine exklusive Sperre für eine Sitzung erwerben muss. Wenn ein Verbraucher eine Sitzungssperre hält, kann kein anderer Verbraucher Nachrichten aus dieser Sitzung verarbeiten, auch wenn der Verbraucher langsam oder vorübergehend angehalten ist. Wenn die Sperrdauer zu kurz ist, kann der Sperrablauf dazu führen, dass nachrichten erneut verarbeitet werden. Wenn die Sperrdauer zu lang ist, verzögert ein blockierter Consumer die Wiederherstellung. Optimieren Sie die Dauer der Sitzungssperre basierend auf der erwarteten Nachrichtenverarbeitungszeit, und implementieren Sie die Sperrverlängerung für längere Ausführungsvorgänge.
Skalierung und Kosten für Verbraucher. Parallelität über Sitzungen hinweg führt zu gleichzeitigen Consumerinstanzen. In einem serverlosen Modell wie Azure Functions entspricht jede aktive Sitzung einer parallelen Ausführung, und in einem dedizierten Modell entspricht sie einer Instanz oder einem Thread. Die Anzahl der aktiven Sitzungen beeinflusst daher die Berechnungskosten direkt. Planen Sie Skalierungsgrenzwerte und Parallelitätssteuerungen für Consumer, um den Durchsatz gegen die Kosten abzuwägen.
Wann dieses Muster verwenden
Verwenden Sie dieses Muster in folgenden Fällen:
- Nachrichten werden in der reihenfolge eintreffen und müssen in derselben Reihenfolge verarbeitet werden.
- Nachrichten können kategorisiert werden, sodass jede Kategorie zu einer unabhängigen Skalierungseinheit für das System wird.
Dieses Muster ist möglicherweise nicht geeignet, wenn:
Sie erwarten extrem hohe Durchsatzszenarien (Millionen von Nachrichten pro Minute), da die FIFO-Anforderung die Skalierung begrenzt, die das System erreichen kann.
Die Nachrichtenbestellung ist nicht erforderlich. Wenn Nachrichten unabhängig in beliebiger Reihenfolge verarbeitet werden können, bietet das Muster "Konkurrierende Verbraucher " eine einfachere horizontale Skalierung ohne den Koordinationsaufwand für die Sitzungssperre.
Arbeitslastgestaltung
Bewerten Sie, wie Sequential Convoy beim Entwurf einer Workload eingesetzt werden kann, um den in den Azure Well-Architected Framework-Säulen behandelten Zielen und Prinzipien gerecht zu werden. Die folgende Tabelle enthält Anleitungen dazu, wie dieses Muster die Ziele jeder Säule unterstützt.
| Säule | So unterstützt dieses Muster die Säulenziele |
|---|---|
| Zuverlässigkeitsentwurfsentscheidungen helfen Ihrer Arbeitsauslastung, ausfallsicher zu werden und sicherzustellen, dass sie nach auftreten eines Fehlers wieder in einen voll funktionsfähigen Zustand versetzt wird. | Dieses Muster verwendet eine sitzungsbasierte FIFO-Reihenfolge, um Racebedingungen, konfliktgefährdete Nachrichtenverarbeitungslogik und andere Problemumgehungen für falsch geordnete Nachrichten zu beseitigen, die zu Fehlfunktionen führen können. - RE:02 Kritische Abläufe - RE:07 Hintergrundaufträge |
Wenn dieses Muster Kompromisse innerhalb einer Säule einführt, sollten Sie sie gegen die Ziele der anderen Säulen berücksichtigen.
Beispiel
Auf Azure können Sie dieses Muster mithilfe Service Bus Nachrichtensitzungen implementieren. Für die Verbraucher können Sie entweder Azure Logic Apps mit dem Service Bus Peek-Lock Connector oder Azure Functions mit dem Service Bus Trigger verwenden.
Wenn ein Produzent die SessionId Eigenschaft für eine Nachricht festlegt, gruppiert Service Bus alle Nachrichten, die dieselbe Sitzungs-ID gemeinsam verwenden, in einer einzigen logischen Sitzung. Ein Consumer akzeptiert eine Sitzung und erhält eine exklusive Sperre dafür. Diese Sperre garantiert, dass immer nur ein Verbraucher Nachrichten für diese Sitzung verarbeitet und dass Nachrichten in FIFO-Reihenfolge eingehen. Andere Verbraucher können gleichzeitig verschiedene Sitzungen akzeptieren und verarbeiten und so einen gruppenübergreifenden parallelen Durchsatz ermöglichen.
Im Beispiel zur Auftragsverfolgung verarbeitet das System jede Ledger-Nachricht in der Reihenfolge, in der sie eingeht, und sendet jede Transaktion an eine andere Warteschlange, wobei die Kategorie auf die Auftrags-ID gesetzt wird. Eine Transaktion umfasst in diesem Szenario niemals mehrere Aufträge, sodass Consumer jede Kategorie parallel, jedoch innerhalb jeder Kategorie nach dem FIFO-Prinzip verarbeiten.
Der Ledger-Prozessor fächert die Nachrichten auf, indem er den Inhalt jeder Nachricht in der ersten Warteschlange entbündelt:
Der Ledger-Prozessor führt drei Schritte aus:
- Durchläuft den Ledger Transaktion für Transaktion.
- Legt die Sitzungs-ID der Nachricht so fest, dass sie der Auftrags-ID entspricht.
- Sendet jede Ledger-Transaktion an eine sekundäre Warteschlange, wobei die Sitzungs-ID auf die Auftrags-ID gesetzt ist.
Die Consumer lauschen an der sekundären Warteschlange und verarbeiten alle Nachrichten mit übereinstimmenden Auftrags-IDs in FIFO-Reihenfolge. Die Benutzer verwenden den peek-lock-Modus.
Die Ledger-Warteschlange ist ein Übergangspunkt von seriell zu parallel: Alle Transaktionen durchlaufen sie sequenziell, bevor sie zur sitzungsbasierten Parallelverarbeitung aufgefächert werden. Diese Serialisierungsphase ist der primäre Skalierbarkeitsengpass, da sie den Durchsatz der gesamten nachgelagerten Pipeline begrenzt. Nachdem der Ledger-Prozessor jedoch Nachrichten an die sekundäre Warteschlange aufgefächert hat, können Consumer unabhängig über Sitzungen hinweg skalieren, eine pro Auftrags-ID.
Unterstützende Technologien
Service Bus-Nachrichtensitzungen: Gruppiert Nachrichten nach Sitzungs-ID und erzwingt die FIFO-Verarbeitung innerhalb jeder Sitzung. Nachrichtensitzungen sind der primäre Azure-Mechanismus zur Implementierung des Musters „Sequenzieller Konvoi“.
Azure Functions Service Bus Trigger: Unterstützt sitzungsbasierte Trigger, mit denen Funktionsinstanzen Nachrichten von einer einzelnen Sitzung gleichzeitig verarbeiten können.
Logic Apps-Service Bus-Connector: Stellt einen Service Bus-Connector mit Peek-Lock-Unterstützung für die Nutzung sitzungsfähiger Warteschlangen in der workflowbasierten Verarbeitung bereit.
Contributors
Microsoft verwaltet diesen Artikel. Die folgenden Mitwirkenden haben diesen Artikel geschrieben.
Hauptautor:
- Naga Venkata Cheruvu | Senior-Architekt für Cloud-Lösungen + KI-Infrastruktur
Um nicht öffentliche LinkedIn-Profile zu sehen, melden Sie sich bei LinkedIn an.
Verwandte Ressourcen
Muster „Konkurrierende Consumer“: Mehrere Consumer rufen Nachrichten parallel aus einer gemeinsam genutzten Warteschlange ab, was den Durchsatz erhöht, aber die Garantien für die Reihenfolge pro Nachricht aufhebt. Das Muster „Sequenzieller Konvoi“ schließt die Lücke bei der Reihenfolge, die durch konkurrierende Consumer entsteht. Sie behebt diese Lücke, indem Nachrichten in Kategorienschlüsselsitzungen aufgeteilt und jede Sitzung sequenziell verarbeitet werden.
Muster „Warteschlangenbasierter Lastenausgleich“: Eine Warteschlange puffert die Arbeit zwischen Producern und Consumern, um Spitzen abzufangen und ungleichmäßige Lasten zu glätten. Das Muster „Sequenzieller Konvoi“ baut auf dieser Pufferung auf, indem es eine sitzungsbasierte Partitionierung hinzufügt, sodass die Warteschlange sowohl die Last über Kategorien hinweg ausgleicht als auch die FIFO-Reihenfolge innerhalb jeder Kategorie beibehält.
Prioritätswarteschlangen-Muster: Nachrichten werden an separate Warteschlangen weitergeleitet oder innerhalb einer Warteschlange priorisiert, sodass Aufgaben mit höherer Priorität vor Aufgaben mit niedrigerer Priorität verarbeitet werden. Wenn die Reihenfolge innerhalb einer Prioritätsebene ebenfalls beibehalten werden muss, kann das Muster „Sequenzieller Konvoi“ mit Prioritätswarteschlangen kombiniert werden, um die FIFO-Verarbeitung innerhalb jeder nach Priorität geschlüsselten Sitzung zu erzwingen.
Peek-Lock-Nachricht (zerstörungsfreies Lesen): Dieser Vorgang ruft atomisch eine Nachricht aus einer Warteschlange oder einem Abonnement ab und sperrt sie zur Verarbeitung.
Geordnete Zustellung korrelierter Nachrichten in Logic Apps mithilfe von Service Bus-Sitzungen: In diesem Blogbeitrag wird die Unterstützung von Logic Apps für das Muster des sequenziellen Konvois beschrieben.