Blog

Microservices: Kopplung vs. Autonomie

Gero Vermaas

Aktualisiert Oktober 22, 2025
7 Minuten

Microservices sind der neueste Architekturstil, der verspricht, alle Probleme zu lösen, die wir bei früheren Architekturstilen hatten. Und genau wie andere Stile hat auch dieser seine eigenen Herausforderungen. Die Herausforderung, die in diesem Blog diskutiert wird, ist die Frage, wie die Kopplung zwischen Microservices realisiert werden kann, während die Services so autonom wie möglich bleiben. Es werden vier Optionen beschrieben und in der Schlussfolgerung wird ein klarer Gewinner ausgewählt.

Für mich sind Microservices autonome Dienste, die die volle Verantwortung für eine Geschäftsfunktion übernehmen. Die volle Verantwortung umfasst Präsentation, API, Datenspeicherung und Geschäftslogik. Autonom ist für mich das Schlüsselwort. Wenn die Dienste autonom sind, können sie ohne oder mit nur minimalen Auswirkungen auf andere Dienste geändert werden. Wenn die Dienste autonom sind, dann sollten betriebliche Probleme in einem Dienst keine Auswirkungen auf die Funktionalität anderer Dienste haben. Das klingt alles nach einer guten Idee, aber Dienste werden nie vollständig isolierte Inseln sein. Ein Dienst ist praktisch immer auf Daten angewiesen, die von einem anderen Dienst bereitgestellt werden. Stellen Sie sich z.B. einen Einkaufswagen-Microservice als Teil eines Webshops vor. Ein anderer Dienst muss Artikel in den Einkaufswagen legen und der Inhalt des Einkaufswagens muss wiederum anderen Diensten zur Verfügung gestellt werden, damit die Bestellung abgeschlossen und versandt werden kann. Die Frage ist nun, wie diese Kopplungen unter Beibehaltung maximaler Autonomie realisiert werden können. Ziel dieses Blogbeitrags ist es, zu erläutern, welches Muster für die Kopplung von Microservices unter Beibehaltung der maximalen Autonomie befolgt werden sollte. rr-ps Ich werde die Muster nach 2 Dimensionen strukturieren: das Interaktionsmuster und die Informationen, die mit diesem Muster ausgetauscht werden. Interaktionsmuster: Anfrage - Antwort vs. Veröffentlichen - Abonnieren.
  • Request-Reply bedeutet, dass ein Dienst eine bestimmte Anfrage nach Informationen stellt (oder eine Aktion durchführt). Er erwartet dann eine Antwort. Der anfragende Dienst muss also wissen, was er anfragen muss und wo er es anfragen muss. Dies könnte immer noch asynchron implementiert werden, und natürlich könnten Sie eine Abstraktion einrichten, so dass der anfragende Dienst die physische Adresse des anderen Dienstes nicht kennen muss, aber der Punkt bleibt, dass ein Dienst explizit eine bestimmte Information anfordert (oder eine Aktion durchführt) und funktionell auf eine Antwort wartet.
  • Publish-Subscribe: Bei diesem Muster meldet sich ein Dienst selbst als an bestimmten Informationen interessiert an oder ist in der Lage, bestimmte Anfragen zu bearbeiten. Die entsprechenden Informationen oder Anfragen werden ihm dann zugestellt und er kann entscheiden, was er damit machen will. In diesem Beitrag gehen wir davon aus, dass es eine Art Middleware gibt, die sich um die Zustellung der veröffentlichten Nachrichten an die abonnierten Dienste kümmert.
Austausch von Informationen: Ereignisse vs. Abfragen/Befehle
  • Ereignisse sind Fakten, über die man nicht streiten kann. Ein Beispiel: Ein Auftrag mit der Nummer 123 wird erstellt. Ereignisse geben nur an, was geschehen ist. Sie beschreiben nicht, was als Folge eines solchen Ereignisses geschehen sollte.
  • Abfragen/Befehle: Beide vermitteln, was geschehen soll. Abfragen sind eine spezifische Anfrage nach Informationen, Befehle sind eine spezifische Aufforderung an den empfangenden Dienst, eine bestimmte Aktion durchzuführen.
Wenn Sie diese beiden Dimensionen in einer Matrix zusammenfassen, ergeben sich 4 Optionen zur Realisierung von Kopplungen zwischen Microservices. Was sind also die Vor- und Nachteile der einzelnen Optionen? Und welche ist die beste, um maximale Autonomie zu erreichen? In der folgenden Beschreibung verwenden wir 2 Dienste, um die einzelnen Muster zu veranschaulichen. Der Dienst Order, der für die Verwaltung von Bestellungen zuständig ist, und der Dienst Shipping, der für den Versand von Waren, z.B. der in einer Bestellung enthaltenen Artikel, verantwortlich ist. Dienste wie diese könnten Teil eines Webshops sein, der dann auch Dienste wie einen Einkaufswagen, einen Produkt(such)dienst usw. enthält.

1. Anfrage/Antwort mit Ereignissen:

rre Bei diesem Muster fragt ein Dienst einen bestimmten anderen Dienst nach Ereignissen, die (seit der letzten Anfrage) stattgefunden haben. Dies impliziert eine starke Abhängigkeit zwischen diesen beiden Diensten. Der Versanddienst muss wissen, mit welchem Dienst er sich für Ereignisse im Zusammenhang mit Bestellungen verbinden muss. Es besteht auch eine Laufzeitabhängigkeit, da der Versanddienst nur dann neue Bestellungen versenden kann, wenn der Bestelldienst verfügbar ist.Da der Versanddienst nur Ereignisse empfängt, muss er anhand der Informationen in diesen Ereignissen selbst entscheiden, wann eine Bestellung versandt werden kann. Der Dienst Order muss nichts über den Versand wissen, er stellt lediglich Ereignisse bereit, aus denen hervorgeht, was mit den Bestellungen geschehen ist, und überlässt die Verantwortung für die Reaktion auf diese Ereignisse vollständig den Diensten, die die Ereignisse anfordern.

2. Anfrage/Antwort mit Befehlen/Abfragen:

rrc In diesem Muster wird der Versanddienst Order Service den Dienst Shipping Service anfordern, um eine Bestellung zu versenden. Dies impliziert eine starke Kopplung, da der Bestelldienst explizit einen bestimmten Dienst anfordert, der sich um den Versand kümmert, und nun muss der Bestelldienst feststellen, wann eine Bestellung versandfertig ist. Er weiß, dass es einen Versanddienst gibt und er weiß sogar, wie er mit diesem interagieren kann. Wenn andere Faktoren, die nicht mit der Bestellung selbst zusammenhängen, vor dem Versand der Bestellung berücksichtigt werden müssen (z.B. der Kreditstatus des Kunden), dann sollte der Bestelldienst dies berücksichtigen, bevor er den Versanddienst mit dem Versand der Bestellung beauftragt. Jetzt ist der Geschäftsprozess in die Architektur eingebettet und kann daher nicht mehr ohne weiteres geändert werden. Auch hier besteht eine Laufzeitabhängigkeit, da der Bestelldienst sicherstellen muss, dass die Versandanfrage erfolgreich an den Versanddienst übermittelt wird.

3. Veröffentlichen und Abonnieren mit Ereignissen

pse In Publish-Subscribe with Events registriert sich der Versanddienst als an Ereignissen im Zusammenhang mit Bestellungen interessiert. Nachdem er sich selbst registriert hat, empfängt er alle Ereignisse im Zusammenhang mit Bestellungen, ohne zu wissen, woher die Bestellungsereignisse stammen. Er ist lose an die Quelle der Auftragsereignisse gekoppelt. Der Versanddienst muss eine Kopie der in den Ereignissen empfangenen Daten aufbewahren, damit er feststellen kann, wann eine Bestellung zum Versand bereit ist. Der Bestelldienst muss keine Kenntnisse über den Versand haben. Wenn mehrere Dienste auftragsbezogene Ereignisse liefern, die relevante Daten für den Versanddienst enthalten, kann der Versanddienst diese nicht erkennen. Wenn (einer) der Dienste, die Auftragsereignisse liefern, ausfällt, bekommt der Versanddienst dies nicht mit, er erhält nur weniger Ereignisse. Der Versanddienst wird hierdurch nicht blockiert.

4. Veröffentlichen-Abbestellen mit Befehlen/Abfragen

pscIn Publish-Subscribe mit Command/Queries registriert sich der Versanddienst als ein Dienst, der Dinge versenden kann. Er empfängt dann alle Befehle, die etwas verschicken wollen. Der Versanddienst muss die Quelle der Versandbefehle nicht kennen und umgekehrt weiß der Bestelldienst nicht, welcher Dienst sich um den Versand kümmern wird. In diesem Sinne sind sie lose gekoppelt. Der Bestelldienst weiß jedoch, dass die Bestellungen versandt werden müssen, da er einen Versandbefehl sendet. Das macht die Kopplung stärker.

Fazit

Nachdem wir nun die vier Optionen beschrieben haben, kehren wir zu der ursprünglichen Frage zurück: Welches der 4 oben genannten Muster bietet die maximale Autonomie? Beide Request-Reply-Muster implizieren eine Laufzeitkopplung zwischen zwei Diensten und das bedeutet eine starke Kopplung. Beide Command/Queries-Muster implizieren, dass ein Dienst weiß, was ein anderer Dienst tun soll (in den obigen Beispielen weiß der Bestelldienst, dass ein anderer Dienst sich um den Versand kümmert) und das impliziert ebenfalls eine starke Kopplung, aber diesmal auf funktionaler Ebene. Damit bleibt nur eine Möglichkeit: 3. Publish-Subscribe mit Ereignissen. In diesem Fall wissen beide Dienste sowohl aus Laufzeit- als auch aus Funktionssicht nichts von der Existenz des jeweils anderen. Für mich ist dies der eindeutige Sieger, wenn es darum geht, eine maximale Autonomie zwischen den Diensten zu erreichen. Die nächste Frage stellt sich sofort: Sollten Sie Dienste immer mit Publish-Subscribe und Ereignissen koppeln? Wenn es Ihnen nur um die maximale Autonomie von Diensten geht, lautet die Antwort ja, aber es gibt noch weitere Faktoren, die berücksichtigt werden sollten. Die Kopplung mit diesem Muster hat ihren Preis: Daten werden repliziert, es müssen Maßnahmen für den Fall ergriffen werden, dass Ereignisse verloren gehen, ereignisgesteuerte Architekturen stellen zusätzliche Anforderungen an die Infrastruktur, es kann zu zusätzlichen Latenzzeiten kommen und vieles mehr. In einem nächsten Beitrag werde ich auf diese Kompromisse eingehen und die Dinge ins rechte Licht rücken. Denken Sie aber daran, dass Publish-Subscribe mit Ereignissen eine gute Grundlage für die Autonomie von Diensten ist.

Verfasst von

Gero Vermaas

Contact

Let’s discuss how we can support your journey.