Eine ereignisgesteuerte Architektur ist ein Entwurfsstil, bei dem Dienste unveränderliche Fakten als Ereignisse melden und Konsumenten unabhängig reagieren. Die Präzision, die Anbieterseiten auslassen, steckt in zwei Wörtern: Ein Ereignis ist ein unveränderlicher Fakt in der Vergangenheitsform – OrderPlaced, nicht PlaceOrder – und der Produzent weiß nicht, wer reagiert, und es interessiert ihn auch nicht. Genau diese Gleichgültigkeit ist die Architektur: Konsumenten kommen hinzu, fallen weg und gehen kaputt, ohne dass der Produzent eine Zeile ändert – Entkopplung im wörtlichsten Sinne. Und EDA ist ein Spektrum, keine Religion: Ein einzelner Webhook ist ereignisgesteuert, eine ganze Streaming-Landschaft ebenfalls, und die meisten gesunden Systeme sind Mischformen.
Das Wichtigste in Kürze
| Frage | Antwort |
|---|---|
| Ein Ereignis ist | Ein unveränderlicher Fakt in der Vergangenheitsform – Konsumenten reagieren, ablehnen können sie nicht |
| Ereignis ≠ Befehl | Fakten an alle Interessierten vs. Aufforderungen an genau einen Handler |
| Die Entscheidungsregel | Arbeit des Produzenten vor den Reaktionen erledigt → Ereignisse; Aufrufer braucht die Antwort → Anfrage-Antwort |
| Die drei Spielarten | Notification · Event-Carried State · Event Sourcing (eine Speicher-Entscheidung) |
| Die laufende Rechnung | Idempotente Konsumenten, Korrelations-IDs, UX für Eventual Consistency |
Ein Fakt, viele Reaktionen
// JavaScript — Cloud Code (cloud/main.js)
// Everyday EDA: the write IS the event; consumers react independently
Parse.Cloud.afterSave('Order', async (req) => {
const order = req.object;
const becamePlaced = order.get('status') === 'placed' &&
req.original?.get('status') !== 'placed';
if (!becamePlaced) return;
// Consumers of one fact — none knows about the others:
await Parse.Cloud.httpRequest({ // fulfillment system (webhook)
method: 'POST', url: process.env.FULFILL_WEBHOOK,
body: { event: 'order.placed', id: order.id },
});
await enqueueConfirmationEmail(order); // async job queue
// Live Query pushes the change to every open dashboard automatically
}); // Flutter / Dart — Back4app Flutter SDK
// The client as event consumer: subscribe to facts, react on arrival
final orders = QueryBuilder<ParseObject>(ParseObject('Order'))
..whereEqualTo('status', 'placed');
final sub = await LiveQuery().client.subscribe(orders);
sub.on(LiveQueryEvent.create, (order) => showNewOrder(order));
// Nobody called this screen — it REACTED to an event, like every
// other consumer of "order placed": fulfillment, email, analytics. // iOS / Swift — Back4app Swift SDK
// The client as event consumer: subscribe to facts, react on arrival
let orders = Order.query("status" == "placed")
let sub = try await orders.subscribe()
sub.handleEvent { _, event in
if case .created(let order) = event { showNewOrder(order) }
}
// Nobody called this screen — it REACTED to an event, like every
// other consumer of "order placed": fulfillment, email, analytics. // Android / Kotlin — Back4app Android SDK
// The client as event consumer: subscribe to facts, react on arrival
val orders = ParseQuery.getQuery<ParseObject>("Order")
orders.whereEqualTo("status", "placed")
val sub = ParseLiveQueryClient.Factory.getClient().subscribe(orders)
sub.handleEvent(SubscriptionHandling.Event.CREATE) { _, order ->
showNewOrder(order)
}
// Nobody called this screen — it REACTED to an event, like every
// other consumer of "order placed": fulfillment, email, analytics. Ein Fakt – eine Bestellung wurde aufgegeben – und vier Konsumenten, von denen keiner die anderen kennt: eine Versandabwicklung, die per Webhook benachrichtigt wird, ein E-Mail-Job in der Queue, ein Analytics-Dienst, der mitzählt, und Dashboards, die sich über ein Live-Abonnement aktualisieren. Ein fünfter Konsument ändert stromaufwärts nichts. Das ist das ganze Argument, in einem einzigen Speichervorgang.
Das Vokabular, entwirrt
Das Begriffschaos der Suchergebnisse, aufgelöst in einer Tabelle – drei Nachrichtenarten, sortiert nach Absicht, nicht nach Transport:
| Befehl (Command) | Ereignis | Abfrage (Query) | |
|---|---|---|---|
| Grammatik | Imperativ: ShipOrder | Vergangenheit: OrderShipped | Frageform |
| Adressat | Ein Handler | Wer abonniert hat | Ein Antwortender |
| Ablehnbar | Ja | Nein – es ist bereits passiert | n. v. |
| Kopplung | Sender kennt den Handler | Produzent kennt niemanden | Aufrufer wartet |
Fowlers Warnung verdient ihr Zitat: Hüten Sie sich vor dem passiv-aggressiven Befehl – einem “Ereignis”, das der Produzent sendet, während er insgeheim verlangt, dass ein bestimmter Konsument handelt. Bricht der Ablauf, sobald dieser Konsument nicht antwortet, war es von Anfang an ein Befehl, und die Bezeichnung “Ereignis” hat die Kopplung nur verdeckt. (Die Infrastrukturwörter – Broker, Router, Bus, Kanal, Topic – sind Beinahe-Synonyme für den mittleren Kasten; der Artikel zu Pub/Sub behandelt diese Maschinerie, deren verallgemeinernde Architektur EDA ist.)
Ereignisgesteuert vs. Anfrage-Antwort
| Anfrage-Antwort | Ereignisgesteuert | |
|---|---|---|
| Zeitliche Kopplung | Aufrufer wartet – Gegenseite muss laufen | Fire-and-forget – Konsumenten holen auf |
| Die Antwort | Geht an den Aufrufer zurück | Es gibt keine Antwort, nur Reaktionen |
| Fehlerverhalten | Sofortiger, sichtbarer Fehler | Widerstandsfähig – und letztendlich konsistent |
| Debugging | Ein Aufrufstack | Korrelations-IDs über alle Sprünge |
| Passend für | Lesezugriffe, Anmeldungen, Zahlungen – alles, was der Aufrufer braucht | Fakten mit unabhängigen Konsumenten |
Die Regel in einem Satz: Braucht der Aufrufer das Ergebnis zum Weiterarbeiten, dann Anfrage-Antwort; ist die Arbeit des Produzenten abgeschlossen, bevor irgendeine Reaktion beginnt, dann Ereignisse. Die Bestellung aufzugeben verlangt eine synchrone Antwort (“hat es geklappt?”); alles danach – E-Mail, Versand, Analytics – sind Reaktionen auf einen Fakt. Genau deshalb sind reale Systeme Mischformen aus Absicht, nicht aus Kompromiss.
Fowlers drei Spielarten – und wo Event Sourcing wirklich hingehört
| Muster | Das Ereignis trägt | Konsumenten | Trade-off |
|---|---|---|---|
| Event Notification | Eine ID und kaum mehr | Fragen die Details nach | Einfach; der Rückrufverkehr koppelt wieder |
| Event-Carried State Transfer | Den vollständigen relevanten Zustand | Halten lokale Kopien | Keine Rückrufe; Duplizierung und Veralten |
| Event Sourcing | Ist das führende System | Rekonstruieren den Zustand per Replay | Perfekte Prüfspur; eine schwergewichtige Speicherentscheidung |
Die Unterscheidung, die Meetings spart: Event Sourcing ist, wie ein System Daten ablegt; EDA ist, wie Systeme miteinander sprechen. Beides lässt sich kombinieren, keines setzt das andere voraus. Noch eine Linie, die Anbieter verwischen: Die Zustellung per Pub/Sub vergisst – wer spät abonniert, verpasst alles, was vorher gesendet wurde –, während Streaming (das geordnete Log nach Kafka-Art) sich erinnert und Konsumenten ab jedem beliebigen Punkt erneut lesen lässt; entscheiden Sie danach, ob die Historie Teil des Produkts ist.
Choreografie vs. Orchestrierung
| Choreografie (EDA-typisch) | Orchestrierung | |
|---|---|---|
| Koordination | Dienste reagieren auf die Ereignisse der anderen | Ein Koordinator kommandiert jeden Schritt |
| Der Workflow lebt | Nirgends explizit – er entsteht | An einer sichtbaren, debugfähigen Stelle |
| Kopplung | Minimal | Der Orchestrator kennt alle |
| Fehlerbehandlung | Kompensierende Ereignisse, verteilt | Zentrale Retry- und Fehlerlogik |
Die spiegelbildliche Regel, die sie mit dem Artikel zur Orchestrierung teilt: Orchestrieren Sie, wenn jemand für das Ergebnis eines Workflows geradestehen muss; choreografieren Sie, wenn Produzenten wirklich nicht interessiert, was danach passiert. Lange fachliche Transaktionen über mehrere Dienste nehmen in beiden Fällen die Form einer Saga an – lokale Transaktionen, verkettet durch Ereignisse oder durch einen Orchestrator, rückgängig gemacht durch Kompensationen statt durch Rollback.
EDA im Alltag – ganz ohne Broker
Der Abschnitt, den Architekturportale nie schreiben: Die meisten App-Entwickler betreiben längst ereignisgesteuerte Muster, ohne dass ein Message Broker in Sicht wäre. Ein beforeSave/afterSave-Trigger ist ein Konsument von Datenänderungsereignissen. Ein Webhook ist ein Ereignis, das über schlichtes HTTP Firmengrenzen überquert. Eine Live Query ist Pub/Sub mit Clients als Subscribern. Ein Hintergrund-Job, den ein Trigger in die Queue stellt, ist ein Ereignis, das asynchrone Arbeit auslöst. Die Code-Tabs oben zeigen genau diesen Stack – das Schreiben ist das Ereignis, der Trigger ist der Router, und die Konsumenten sind ein Webhook, eine Queue und ein Abonnement. Dedizierte Broker (Kafka, RabbitMQ, NATS – mit CloudEvents als Standardumschlag) rechtfertigen ihr Betriebsgewicht, sobald Ereignisvolumen, Replay und teamübergreifende Verträge es verlangen; die Architektur beginnt viel früher, und die Frage “brauche ich einen Broker?” beantwortet sich meist von selbst: noch nicht.
Typische Anwendungsfälle
- Bestell- und Zahlungsabläufe – ein Fakt, viele Abteilungen: die kanonische E-Commerce-Pipeline.
- Systemübergreifende Integration – Dienste verschiedener Teams reagieren ohne direkte Aufrufe und ohne gemeinsame Deployments.
- Echtzeit-Features – Dashboards, Feeds und Präsenz als Ereigniskonsum auf Client-Seite.
- Stoßweise Lasten – Queues puffern die Spitzen, damit Konsumenten sie im eigenen Tempo abarbeiten.
- Prüfspur und Replay – Streaming-Logs, bei denen “was ist wann passiert” selbst das Produkt ist.
Sollten Sie ereignisgesteuert arbeiten? Eine Entscheidungsmatrix
| Situation | Greifen Sie zu |
|---|---|
| Ein Fakt, mehrere unabhängige Konsumenten | Ereignisse – ihr Heimspiel |
| Aufrufer braucht die Antwort, um weiterzumachen | Anfrage-Antwort, ohne schlechtes Gewissen |
| Workflow mit Verantwortlichem und SLA | Orchestrierung – kommandieren Sie die Schritte |
| Reaktionen innerhalb einer App (E-Mail bei der Registrierung) | Trigger + Jobs – EDA im Alltag |
| Firmenübergreifende Benachrichtigungen | Webhooks |
| Streams mit hohem Volumen, Replay und mehreren Teams | Ein echter Broker – jetzt hat er sich seinen Platz verdient |
Grenzen und Trade-offs
- Dem Debugging fehlt der Aufrufstack. Eine Anfrage, die sich in fünf asynchrone Sprünge auffächert, ist nur über Korrelations-IDs nachvollziehbar, die ab dem ersten Ereignis mitgeführt werden – nachrüsten ist eine Qual; verdrahten Sie sie ab dem ersten Tag.
- Eventual Consistency reicht bis in die Oberfläche. Der Nutzer ändert sein Profil, und der nächste Bildschirm zeigt den alten Namen; entweder Sie gestalten die UX dafür, oder Sie halten diesen Pfad synchron.
- Duplikate gehören zum Vertrag. At-least-once-Zustellung macht idempotente Konsumenten zur Pflicht – derselbe Vertrag, den Queues auferlegen, weil es dieselbe Maschinerie ist.
- Schemas ändern sich unter den Füßen der Konsumenten. Ereignisse sind Verträge mit unbekannten Subscribern: nur additive Änderungen, versionierte Topics für Brüche und überall tolerante Leser.
- Entstehende Workflows verstecken sich. Reine Choreografie heißt, dass niemand auf den Geschäftsprozess zeigen kann; sobald Prüfer oder Kollegen in der Rufbereitschaft das brauchen, ergänzen Sie den Orchestrator.
Ereignisgesteuerte Muster mit Back4app
Back4app ist eine Open-Source-Plattform für Backend as a Service (BaaS), die eine verwaltete Datenbank, automatisch generierte REST- und GraphQL-APIs, Authentifizierung, Dateispeicher und Serverless-Funktionen mit Cloud Code kombiniert. Der Abschnitt zur Alltags-EDA ist die Feature-Liste der Plattform, gelesen als Architektur: Jedes Speichern ist ein Ereignis, afterSave-Trigger sind serverseitige Konsumenten mit dem vollen JavaScript-Ökosystem, Live Queries verteilen Fakten über verwaltete WebSockets an die Clients, Webhooks tragen sie zu externen Systemen, und Hintergrund-Jobs fangen die langsamen Reaktionen ab – die Code-Tabs zeigen die gesamte Schleife ab einem einzigen Bestellvorgang. Die Disziplinen, auf denen dieser Artikel besteht, bleiben Ihre (idempotente After-Hooks, Denken in der Vergangenheitsform, synchron dort, wo der Aufrufer Antworten braucht), während die brokerförmige Infrastruktur – Fan-out, Zustellung, Verbindungsflotten – als Plattformverhalten geliefert wird; und der spätere Umstieg auf einen dedizierten Streaming-Broker ist eine Ergänzung dieser Architektur, keine Neufassung.
Häufige Fragen
Was ist eine ereignisgesteuerte Architektur, einfach erklärt?
Komponenten verkünden, dass etwas passiert ist – ein Ereignis –, statt sich gegenseitig aufzurufen, und jede interessierte Komponente reagiert in ihrem eigenen Takt. Rundfunk statt Telefonat: Die Arbeit des Senders endet mit der Ansage, und Zuhörer kommen und gehen, ohne dass sich beim Sender etwas ändert.
Was ist der Unterschied zwischen einem Ereignis und einem Befehl?
Die Absicht. Ein Befehl ist eine Aufforderung an genau einen Empfänger, der sie ablehnen kann – ShipOrder. Ein Ereignis ist ein Fakt in der Vergangenheitsform, gesendet an alle, die es interessiert – OrderShipped. Die Falle ist der "passiv-aggressive Befehl": ein Ereignis, das insgeheim erwartet, dass ein ganz bestimmter Konsument handelt – also ein Befehl im Kostüm.
Was ist der Unterschied zwischen ereignisgesteuert und Anfrage-Antwort?
Die Kopplung in der Zeit. Anfrage-Antwort ist synchron – der Aufrufer wartet, braucht die Antwort und scheitert, wenn die Gegenseite nicht erreichbar ist. Ereignisse sind Fire-and-forget – widerstandsfähig und entkoppelt, aber letztendlich konsistent. Die Regel: Braucht der Aufrufer das Ergebnis zum Weiterarbeiten, dann Anfrage-Antwort; ist die Arbeit des Produzenten erledigt, bevor die Reaktionen beginnen, dann Ereignisse.
Was ist der Unterschied zwischen EDA und Pub/Sub?
Die Ebene. Pub/Sub ist ein Messaging-Muster – ein Zustellmechanismus, von Publishern über Topics zu Subscribern. EDA ist der Architekturstil, der üblicherweise darauf aufsetzt, zusammen mit Queues und Streams. Pub/Sub ist die Verrohrung; ereignisgesteuert ist die Entwurfsphilosophie, der diese Verrohrung dient.
Was sind Event Notification, Event-Carried State Transfer und Event Sourcing?
Fowlers drei verschiedene Muster, die sich unter einem Namen verstecken. Notification: dünne Ereignisse, Konsumenten fragen die Details nach. State Transfer: Die Ereignisse tragen die vollständigen Daten, Konsumenten halten lokale Kopien. Sourcing: eine Persistenzentscheidung – jede Änderung als Ereignis speichern und den Zustand per Replay rekonstruieren. Das dritte beschreibt, wie ein System Daten ablegt, nicht wie Systeme miteinander sprechen.
Was ist der Unterschied zwischen Choreografie und Orchestrierung?
Choreografie: Dienste reagieren auf die Ereignisse der anderen, ohne zentrales Gehirn – maximale Entkopplung, aber der Workflow existiert nirgends explizit. Orchestrierung: Ein Koordinator kommandiert jeden Schritt – sichtbar und debugfähig, um den Preis eines zentralen Kopplungspunkts. Die Regel: Orchestrieren Sie, wenn jemand für das Ergebnis geradestehen muss; choreografieren Sie, wenn Produzenten wirklich nicht interessiert, was danach passiert.
Wie gehe ich mit doppelten und unsortierten Ereignissen um?
Durch Entwurf, nicht durch Hoffnung: Broker liefern at-least-once, also müssen Konsumenten idempotent sein – nach Ereignis-ID deduplizieren oder Handler schreiben, deren Wiederholung folgenlos bleibt ("Status auf versendet setzen", niemals "umschalten"). Die Reihenfolge ist nur pro Partition oder Schlüssel garantiert; eine Architektur, die globale Ordnung verlangt, kämpft gegen ihr eigenes Transportmittel.
Wann sollten Sie eine ereignisgesteuerte Architektur einsetzen?
Wenn ein Fakt mehrere unabhängige Konsumenten hat, wenn die Last stoßweise auftritt und Puffern hilft, wenn Systeme sich integrieren müssen, ohne einander zu kennen, oder wenn eine Prüfspur der Änderungen einen Wert hat. Wann nicht: einfaches CRUD, Lesezugriffe, Operationen mit sofortiger starker Konsistenz und Teams ohne Appetit auf verteilte Systeme.