Enterprise Integration Patterns

Routing

Enterprise Integration Patterns · Gruppe 5 von 8

Lesestand

Routing ist das Herz der Integration: Wie gelangt eine Nachricht zu dem System, das sie verarbeiten soll? Diese Gruppe ist mit zwölf Mustern die größte. Die ersten vier entscheiden über den Weg einer Nachricht. Die nächsten drei zerlegen und verbinden Nachrichten oder bringen sie in Reihenfolge. Die letzten fünf sind zusammengesetzte Muster, die mehrere Bausteine zu größeren Abläufen kombinieren, bis hin zur zentralen Steuerung ganzer Geschäftsprozesse.

  • Anwendung
  • Integrationskomponente
  • Kanal
  • Nachricht
  • Datenbank / Speicher

29. Content-Based Router · Inhaltsbasierter Router

ShopContent-BasedRouterLager BücherLager TechnikKühllagerliest "kategorie"
Der Router schaut in jede Bestellung und schickt sie je nach Warenkategorie an das passende Lager.

Die Idee

Der Content-Based Router ist die häufigste Form des Message Routers: Er untersucht den Inhalt jeder Nachricht, also Header-Felder oder Werte im Body, und leitet sie danach an genau einen von mehreren Ausgangskanälen weiter. Die Regeln stehen an einer zentralen Stelle, nicht beim Sender und nicht bei den Empfängern.

Beispiel

Ein Händler hat drei Lager: eines für Bücher, eines für Elektronik und ein Kühllager für Lebensmittel. Der Shop schickt alle Bestellungen in einen Kanal. Der Router liest das Feld kategorie und verteilt die Bestellungen. Ob eine Bestellung nach Größe, Land, Kundenstatus oder Betrag verteilt wird, ist nur eine Frage der Regel.

Worauf achten

Der Router muss alle Ziele und ihre Zuständigkeiten kennen. Kommt ein neues Ziel hinzu, muss er angepasst werden. Das ist bei wenigen, stabilen Zielen gerade richtig, bei häufigen Änderungen hilft der Dynamic Router (Muster 31). Jeder Content-Based Router braucht außerdem eine Regel für Nachrichten, auf die keine Bedingung passt, etwa einen Standardkanal oder den Invalid Message Channel.

In der Praxis

In Apache Camel choice().when(header("kategorie").isEqualTo("buch")).to(...), in Spring Integration @Router oder HeaderValueRouter, in RabbitMQ Topic- und Header-Exchanges, die anhand von Routing-Keys bzw. Header-Werten verteilen.

30. Message Filter · Nachrichtenfilter

ShopFilterVertriebverworfennur Bestellungenüber 1.000 €
Der Vertrieb will nur über Großbestellungen informiert werden. Alle anderen Nachrichten fallen heraus.

Die Idee

Ein Message Filter ist ein Router mit nur einem Ausgang: Nachrichten, die eine Bedingung erfüllen, lässt er durch. Alle anderen verwirft er. So erhält ein Empfänger nur die Nachrichten, die ihn wirklich interessieren, ohne sich selbst durch alle anderen arbeiten zu müssen.

Beispiel

Der Vertrieb möchte bei jeder Bestellung über 1.000 € benachrichtigt werden, um den Kunden persönlich anzurufen. Er hängt einen Filter an das Topic mit allen Bestellungen. Der Filter lässt nur große Bestellungen durch, der Vertrieb bekommt nur noch das, was er braucht.

Worauf achten

Filtern ist endgültig: Verworfene Nachrichten sind für diesen Weg weg. Das ist bei einem Publish-Subscribe Channel unproblematisch, weil jeder Abonnent seine eigene Kopie hat und filtern kann, wie er will. In einem Point-to-Point Channel dagegen kann ein Filter Nachrichten vernichten, die eigentlich jemand anderes gebraucht hätte. Für „mehrere Empfänger mit verschiedenen Interessen“ gibt es zwei Lösungen: ein Topic mit einem Filter pro Abonnent, oder einen Content-Based Router.

In der Praxis

filter() in Camel, @Filter in Spring Integration, Message Selectors in JMS (betrag > 1000 als SQL-ähnlicher Ausdruck), Filter-Policies bei Amazon SNS. In Java Streams ist filter() dasselbe Prinzip für Daten im Speicher.

31. Dynamic Router · Dynamischer Router

ShopDynamic RouterDE → Lager KölnAT → Lager WienCH → Lager ZürichLager KölnLager WienLager Zürich"Ich bin zuständig für CH"neues Lager meldet sich an,Router lernt die Regel
Das neue Lager in Zürich meldet sich beim Router an. Ab sofort bekommt es die Bestellungen aus der Schweiz.

Die Idee

Beim Content-Based Router sind die Regeln fest einprogrammiert. Der Dynamic Router hält seine Routing-Tabelle zur Laufzeit aktuell. Die möglichen Empfänger melden sich über einen eigenen Steuerkanal bei ihm an und teilen mit, für welche Nachrichten sie zuständig sind. Der Router trägt das in seine Tabelle ein und verteilt ab sofort danach.

Beispiel

Ein Händler eröffnet ein neues Lager in Zürich. Beim Start schickt das Lager eine Nachricht an den Steuerkanal: „Ich bin zuständig für Lieferungen in die Schweiz.“ Der Router übernimmt die Regel. Niemand muss den Router umprogrammieren oder neu starten. Schließt das Lager, meldet es sich wieder ab.

Worauf achten

Die Flexibilität hat ihren Preis: Was passiert, wenn sich zwei Empfänger für dasselbe melden? Wenn ein Empfänger abstürzt, ohne sich abzumelden? Wenn der Router neu startet und seine Tabelle vergisst? Ein Dynamic Router braucht deshalb Regeln für Konflikte, eine dauerhafte Speicherung seiner Tabelle und am besten regelmäßige Lebenszeichen der Empfänger. Außerdem lässt sich das Verhalten des Systems schwerer nachvollziehen, weil die Regeln nirgends im Code stehen.

In der Praxis

Service-Registries wie Consul oder Eureka zusammen mit Load-Balancern, die bei der Registry nachschlagen, sind die heute verbreitetste Form. In Camel gibt es dynamicRouter() mit einer Methode, die bei jeder Nachricht das Ziel berechnet.

32. Recipient List · Empfängerliste

ShopRecipientListLagerBuchhaltungZoll-Meldungdiesmal nichtempfänger: lager, buchhaltungInland: kein Zoll nötig
Für eine Inlandsbestellung ermittelt die Recipient List zwei Empfänger. Eine Auslandsbestellung ginge zusätzlich an den Zoll.

Die Idee

Eine Recipient List schickt eine Nachricht an mehrere Empfänger, aber nicht pauschal an alle wie ein Publish-Subscribe Channel. Für jede Nachricht wird einzeln berechnet, wer sie bekommen soll. Dann erhält jeder Empfänger auf der Liste eine Kopie.

Beispiel

Eine Inlandsbestellung geht an das Lager und die Buchhaltung. Eine Bestellung ins Nicht-EU-Ausland geht zusätzlich an das System für Zollmeldungen. Eine Bestellung mit Gefahrgut geht außerdem an die Sicherheitsabteilung. Die Recipient List prüft jede Bestellung und stellt die passende Liste zusammen.

Worauf achten

Die Liste kann auf zwei Arten entstehen: Die Recipient List berechnet sie anhand von Regeln, oder der Sender schreibt sie gleich in den Header der Nachricht. Im zweiten Fall muss der Sender seine Empfänger kennen, was die Entkopplung schwächt. Der Unterschied zu einem Publish-Subscribe Channel: Dort entscheiden die Empfänger, ob sie zuhören. Hier entscheidet die Recipient List, wer etwas bekommt. Werden die Antworten der Empfänger anschließend wieder eingesammelt, entsteht Scatter-Gather (Muster 37).

In der Praxis

recipientList() in Camel, RecipientListRouter in Spring Integration, und im Alltag jede E-Mail mit mehreren Empfängern in An und CC.

33. Splitter · Aufteiler

ShopBestellung: 3 PositionenSplitterPos. 1: BuchPos. 2: KopfhörerPos. 3: Käseeine Nachricht rein, drei raus
Eine Bestellung mit drei Positionen wird in drei einzelne Nachrichten zerlegt.

Die Idee

Ein Splitter nimmt eine Nachricht, die mehrere Elemente enthält, und zerlegt sie in einzelne Nachrichten, eine pro Element. Jedes Element kann danach unabhängig weiterverarbeitet, geroutet oder parallel bearbeitet werden.

Beispiel

Eine Bestellung enthält ein Buch, Kopfhörer und Käse. Diese drei Artikel kommen aus drei verschiedenen Lagern. Der Splitter erzeugt aus der Bestellung drei Positionsnachrichten. Ein nachgeschalteter Content-Based Router schickt jede an das richtige Lager.

Worauf achten

Jede Teilnachricht sollte genug Kontext mitnehmen, um allein verständlich zu sein: Bestellnummer, Kunde, Lieferadresse. Damit die Teile später wieder zusammengeführt werden können, bekommen sie eine gemeinsame Kennung, ihre Nummer und die Gesamtzahl der Teile (wie bei der Message Sequence aus Gruppe 4). Der Splitter hat sein natürliches Gegenstück im Aggregator (Muster 34).

In der Praxis

split() in Camel, etwa split(body().tokenize("\n")) für eine Zeile pro Nachricht, @Splitter in Spring Integration. In Java Streams entspricht flatMap() dem Splitter.

34. Aggregator · Zusammenführer

Buch: versandtKopfhörer: versandtKäse: versandtAggregatorKunde(E-Mail)Alles versandtsammelt nach Bestellnummer,bis alle 3 da sind
Erst wenn alle drei Versandmeldungen da sind, erhält der Kunde eine einzige E-Mail.

Die Idee

Der Aggregator ist das Gegenstück zum Splitter: Er sammelt zusammengehörige Nachrichten und erzeugt daraus eine einzige neue Nachricht. Dafür muss er zustandsbehaftet sein. Er merkt sich die bisher eingegangenen Teile, bis die Gruppe vollständig ist.

Beispiel

Die drei Positionen einer Bestellung wurden von drei Lagern verschickt, und jedes Lager meldet seinen Versand. Der Kunde soll aber nicht drei E-Mails bekommen. Der Aggregator sammelt die Versandmeldungen nach Bestellnummer, und erst wenn alle drei vorliegen, erzeugt er eine Nachricht „Ihre Bestellung ist vollständig versandt“.

Worauf achten

Jeder Aggregator braucht Antworten auf drei Fragen:

  • Korrelation: Welche Nachrichten gehören zusammen? Meist über eine gemeinsame ID wie die Bestellnummer.
  • Vollständigkeit: Wann ist eine Gruppe fertig? Wenn alle erwarteten Teile da sind, nach einer festen Wartezeit, oder sobald das erste gute Ergebnis vorliegt.
  • Zusammenführung: Wie wird aus vielen Nachrichten eine? Alle sammeln, summieren, das beste Ergebnis wählen.

Besonders wichtig ist der Fall, dass ein Teil nie ankommt. Ohne Zeitlimit wartet der Aggregator ewig, und unvollständige Gruppen füllen nach und nach den Speicher.

In der Praxis

aggregate() in Camel mit AggregationStrategy und completionSize() bzw. completionTimeout(), @Aggregator mit ReleaseStrategy in Spring Integration, Windowing in Kafka Streams. In Java Streams entspricht Collectors.groupingBy() dem Grundgedanken.

35. Resequencer · Neuordner

Lager213Resequencerpuffert und sortiert321BuchhaltungAnkunft: 3, 1, 2Weitergabe: 1, 2, 3Nachricht 3 wird festgehalten, bis 1 und 2 durch sind
Die Buchungen kommen durcheinander an. Der Resequencer gibt sie erst in der richtigen Reihenfolge weiter.

Die Idee

Nachrichten können unterwegs ihre Reihenfolge verlieren, etwa weil sie über verschiedene Wege laufen oder parallel verarbeitet werden. Der Resequencer puffert eingehende Nachrichten und gibt sie erst in der richtigen Reihenfolge weiter. Dafür braucht jede Nachricht eine laufende Nummer.

Beispiel

Ein Lager meldet Buchungen: 1 Wareneingang, 2 Entnahme, 3 Inventurkorrektur. Weil die Meldungen von mehreren Workern parallel verschickt werden, kommen sie in der Reihenfolge 3, 1, 2 an. Die Buchhaltung braucht sie aber in der richtigen Reihenfolge, sonst wäre der Bestand zwischendurch negativ. Der Resequencer hält Nachricht 3 fest, gibt 1 sofort weiter, dann 2 und schließlich 3.

Worauf achten

Fehlt eine Nachricht dauerhaft, staut sich alles hinter ihr. Der Resequencer braucht deshalb eine Höchstwartezeit und eine Regel, was dann passiert: die Lücke melden und weitermachen, oder anhalten. Außerdem muss die Pufferkapazität begrenzt sein. Oft lässt sich das Problem vermeiden, indem man von vornherein dafür sorgt, dass zusammengehörige Nachrichten denselben Weg nehmen, wie es Kafka mit Partitionen macht.

In der Praxis

resequence() in Camel mit Batch- oder Stream-Modus, Resequencer in Spring Integration. Im Netzwerk erledigt TCP genau diese Aufgabe für Datenpakete.

36. Composed Message Processor · Zusammengesetzter Verarbeiter

Composed Message ProcessorShopSplitter3×RouterLager BücherLager TechnikKühllagerAggregatorKundeJede Position wird vom zuständigen Lager geprüft, das Ergebnis als Ganzes zurückgegeben
Splitter, Router und Aggregator arbeiten zusammen: Jede Position geht an ihr Lager, das Ergebnis kommt gebündelt zurück.

Die Idee

Der Composed Message Processor ist kein neuer Baustein, sondern eine bewährte Kombination aus drei bekannten: Ein Splitter zerlegt eine Nachricht in Teile, ein Router schickt jeden Teil an das zuständige System, und ein Aggregator setzt die Ergebnisse wieder zu einer Nachricht zusammen. Von außen sieht das Ganze aus wie ein einziger Filter: eine Nachricht rein, eine raus.

Beispiel

Vor der Bestätigung einer Bestellung soll jede Position auf Verfügbarkeit geprüft werden. Bücher prüft das Bücherlager, Elektronik das Technik-Lager, Lebensmittel das Kühllager. Der Splitter zerlegt die Bestellung, der Router schickt jede Position an ihr Lager, und der Aggregator führt die Antworten zu „Position 1 lieferbar, Position 2 lieferbar, Position 3 in zwei Tagen“ zusammen.

Worauf achten

Alle Schwierigkeiten der Einzelteile treffen hier zusammen: Der Aggregator muss wissen, wie viele Teile er erwarten kann, und er braucht ein Zeitlimit für Lager, die nicht antworten. Der Unterschied zu Scatter-Gather (Muster 37): Hier bekommt jedes Ziel einen anderen Teil der Nachricht. Bei Scatter-Gather bekommen alle Ziele dieselbe Anfrage.

In der Praxis

In Camel lässt sich das kompakt mit split(..., aggregationStrategy) bauen, wobei der Splitter die Ergebnisse selbst einsammelt. Typische Einsatzgebiete sind Verfügbarkeitsprüfungen, Preisberechnungen pro Position und die Validierung zusammengesetzter Dokumente.

37. Scatter-Gather · Verteilen und Einsammeln

EinkaufVerteilenLieferant A12,40 €Lieferant B11,90 €Lieferant C13,10 €AggregatorB: 11,90 €dieselbe Anfrage an allewählt das beste
Die Preisanfrage geht an drei Lieferanten. Der Aggregator wählt das günstigste Angebot.

Die Idee

Scatter-Gather schickt dieselbe Anfrage an mehrere Empfänger (Scatter, „verstreuen“) und sammelt deren Antworten anschließend wieder ein (Gather, „einsammeln“). Ein Aggregator fasst die Antworten zu einem Ergebnis zusammen, etwa indem er die beste auswählt oder alle zusammenführt.

Beispiel

Der Einkauf braucht 500 Kartons. Er schickt eine Preisanfrage gleichzeitig an drei Lieferanten. Die Angebote kommen nach und nach zurück: 12,40 €, 11,90 € und 13,10 €. Der Aggregator wartet höchstens zwei Minuten und gibt dann das günstigste Angebot, Lieferant B, an den Einkauf weiter.

Worauf achten

Verteilt wird entweder über einen Publish-Subscribe Channel, bei dem jeder interessierte Lieferant zuhören kann, oder über eine Recipient List mit einer festen Auswahl. Entscheidend ist die Abschlussregel des Aggregators: auf alle warten, bis zu einem Zeitlimit warten, oder schon beim ersten ausreichend guten Angebot aufhören. Ein langsamer oder ausgefallener Empfänger darf nicht das ganze Ergebnis blockieren.

In der Praxis

Preisvergleiche und Ausschreibungen, Flug- und Hotelsuchen, die viele Anbieter parallel abfragen, verteilte Suchen über mehrere Datenbanken. In Camel multicast().parallelProcessing() mit einer AggregationStrategy, in Spring Integration ScatterGatherHandler.

38. Routing Slip · Laufzettel

ShopAdresse prüfenSteuer berechnenGeschenk-verpackungLagerLaufzettel im Header (für diese Bestellung)1. Adresse prüfen ✓ erledigt2. Steuer berechnen ✓ erledigt3. Geschenkverpackung → als Nächstesjeder Schritt liest den Zettel und schickt die Nachricht zum nächsten
Diese Bestellung soll als Geschenk verpackt werden. Ihr Laufzettel enthält deshalb einen dritten Schritt.

Die Idee

Bei einem Routing Slip wird die Route einer Nachricht gleich am Anfang festgelegt und als Liste von Stationen in den Header geschrieben, wie ein Laufzettel, der an einer Akte klebt. Jede Station erledigt ihre Arbeit, hakt sich auf dem Zettel ab und schickt die Nachricht an die nächste Station auf der Liste. Die Stationen selbst kennen einander nicht.

Beispiel

Bestellungen durchlaufen je nach Art unterschiedliche Schritte. Jede wird auf eine gültige Adresse geprüft und bekommt die Steuer berechnet. Wurde Geschenkverpackung gewählt, kommt ein dritter Schritt hinzu, bei Firmenkunden eine Bonitätsprüfung. Am Eingang wird für jede Bestellung der passende Laufzettel erstellt. Danach läuft sie ohne zentrale Steuerung durch genau die Stationen, die sie braucht.

Worauf achten

Der Routing Slip eignet sich für lineare Abläufe, deren Schritte am Anfang feststehen. Verzweigungen, Schleifen oder Entscheidungen, die erst von einem Zwischenergebnis abhängen, lassen sich damit kaum abbilden. Dafür gibt es den Process Manager (Muster 39). Ein Vorteil: Weil die Route in der Nachricht steht, lässt sich jederzeit nachvollziehen, wo eine Nachricht gerade ist und was noch fehlt.

In der Praxis

routingSlip() in Camel mit einem Header, der die Liste der Endpunkte enthält, RoutingSlip in Spring Integration. In verteilten Systemen gibt es denselben Gedanken bei choreografierten Sagas, in denen jeder Dienst den nächsten Schritt aus der Nachricht liest.

39. Process Manager · Prozesssteuerung

ShopProcess ManagerBestellung 4711Zahlung: ✓Lager: ✓Versand: läuftZahlungLagerVersandBefehle hin, Antworten zurückkennt denAblauf nichthält den Zustand jedes Vorgangs
Der Process Manager steuert die Bestellung Schritt für Schritt und merkt sich, wie weit jeder Vorgang ist.

Die Idee

Für komplexe Abläufe mit Verzweigungen, Wartezeiten und Fehlerbehandlung gibt es eine zentrale Steuerung: den Process Manager. Er kennt den gesamten Ablauf, schickt jedem beteiligten Dienst zur richtigen Zeit einen Auftrag, wartet auf dessen Antwort und entscheidet dann über den nächsten Schritt. Für jeden laufenden Vorgang speichert er den aktuellen Stand.

Beispiel

Eine Bestellung durchläuft: Zahlung einziehen, Ware reservieren, Versand beauftragen. Schlägt die Zahlung fehl, soll der Kunde benachrichtigt und die Reservierung aufgehoben werden. Ist ein Artikel nicht vorrätig, wird zwei Tage gewartet und erneut geprüft. Der Process Manager bildet diese Regeln ab. Die Dienste Zahlung, Lager und Versand kennen den Ablauf nicht, sie erledigen nur ihre jeweilige Aufgabe.

Worauf achten

Der Process Manager ist das mächtigste Routing-Muster. Er kann alles, was die anderen können, und mehr. Dafür ist er auch das aufwendigste: Er braucht einen dauerhaften Speicher für seine Vorgänge, muss Zeitüberschreitungen erkennen und im Fehlerfall bereits erledigte Schritte rückgängig machen können. Der Gegenentwurf ist die Choreografie, bei der Dienste nur auf Events reagieren und es keine zentrale Steuerung gibt. Das ist lockerer gekoppelt, aber der Gesamtablauf ist nirgends sichtbar.

In der Praxis

Workflow-Engines wie Camunda, Temporal oder AWS Step Functions, orchestrierte Sagas in Microservice-Architekturen, BPMN-Prozesse. In Camel und Spring Integration lassen sich einfache Process Manager mit Routen und einem Zustandsspeicher bauen.

40. Message Broker · Nachrichtenvermittler

ohne Broker: 15 VerbindungenBrokermit Broker: 6 Verbindungenstatt
Sechs Anwendungen: links jede mit jeder verbunden, rechts alle nur mit dem Broker.

Die Idee

Ein Message Broker ist ein zentraler Vermittler, über den alle Anwendungen ihre Nachrichten austauschen. Statt dass jede Anwendung jede andere kennt und mit ihr verbunden ist, kennt jede nur den Broker. Er übernimmt Routing, Übersetzung und Zustellung. Das Buch beschreibt ihn als Muster auf Architekturebene: Viele der anderen Routing-Muster werden im Broker zusammengefasst.

Beispiel

Ein Unternehmen hat sechs Anwendungen, die Daten austauschen. Direkt miteinander verbunden wären das bis zu 15 einzelne Schnittstellen, und bei der siebten Anwendung kämen sechs weitere hinzu. Mit einem Broker hat jede Anwendung genau einen Anschluss. Eine neue Anwendung braucht ebenfalls nur einen.

Worauf achten

Diese Architektur heißt auch Hub and Spoke, Nabe und Speichen. Ihr Vorteil ist die Übersicht: Alle Integrationsregeln liegen an einem Ort. Ihr Risiko ist dasselbe: Der Broker wird zum Engpass und zum zentralen Ausfallpunkt. Er muss deshalb hochverfügbar und skalierbar betrieben werden. Wandert zu viel Geschäftslogik in den Broker, entsteht ein schwer wartbarer Zentralbaustein. Der heutige Trend geht deshalb zu „dummen“ Brokern, die nur transportieren, während die Logik in den Anwendungen bleibt.

In der Praxis

Das Wort „Broker“ wird heute meist für die Messaging-Server selbst verwendet: RabbitMQ, ActiveMQ, Kafka. Im Sinne des Musters, also mit zentraler Routing- und Übersetzungslogik, entsprechen ihm eher Integrationsplattformen wie Apache Camel als zentraler Dienst, MuleSoft oder klassische Enterprise Service Buses.

Die Routing-Muster im Überblick

MusterEingang → AusgangEntscheidet anhand
Content-Based Router1 → einer von vielenInhalt der Nachricht, feste Regeln
Message Filter1 → 1 oder keinerBedingung
Dynamic Router1 → einer von vielenRegeln, die sich zur Laufzeit ändern
Recipient List1 → mehrereberechnete Empfängerliste
Splitter1 Nachricht → viele NachrichtenStruktur des Inhalts
Aggregatorviele Nachrichten → 1 NachrichtKorrelation und Vollständigkeit
Resequencerviele → viele, sortiertlaufende Nummer
Composed Message Processor1 → 1 (intern zerlegt)Splitter + Router + Aggregator
Scatter-Gather1 → 1 (intern verteilt)Verteilen + Aggregator
Routing Slipfeste Folge von StationenLaufzettel in der Nachricht
Process Managerbeliebiger Ablaufzentraler Zustand und Ablaufregeln
Message Brokeralle ↔ alle über einen KnotenArchitektur: Nabe und Speichen