Pub/Sub ist ein Messaging-Muster, bei dem Publisher Nachrichten an Topics auf einem Broker senden und jeder Subscriber eines Topics eine Kopie erhält. Sein ganzer Wert liegt in dem, was die Beteiligten nicht wissen: Publisher erfahren nie, wer zuhört, Subscriber nie, wer gesendet hat – die Indirektion des Brokers entkoppelt sie im Raum (verschiedene Systeme), in der Zeit (Subscriber dürfen offline sein) und in der Synchronisation (das Publizieren kehrt sofort zurück). Subscriber hinzufügen, ohne die Publisher anzufassen: Das ist die stille Stärke des Musters.
Das Wichtigste in Kürze
| Frage | Antwort |
|---|---|
| Die Beteiligten | Publisher → Nachricht → Topic → Broker → Subscriber (jeder bekommt eine Kopie) |
| vs. eine Queue | Eine Queue verteilt Arbeit an einen Konsumenten; Pub/Sub vervielfältigt sie an alle |
| vs. Observer | Observer läuft im Prozess und synchron; Pub/Sub läuft über einen Broker und asynchron |
| Die Standardhaltung | At-least-once-Zustellung + idempotente Handler |
| Das Kleingedruckte | Keine Antworten, keine Reihenfolge ab Werk, keine atomaren Transaktionen über den Broker |
Das Muster im Code
Jede Pub/Sub-API lässt sich auf zwei Verben reduzieren, egal welcher Broker:
// Subscriber — melden Interesse an einem Topic an
broker.subscribe('orders.paid', (msg) => fulfill(msg)); // Dienst A
broker.subscribe('orders.paid', (msg) => notifyUser(msg)); // Dienst B — eigene Kopie
// Publisher — fire and forget
broker.publish('orders.paid', { orderId: 'o-1187' });
// Der Publisher erfährt nie, wer sie empfangen hat — oder ob überhaupt jemand.
Dieselbe Form am Client-Rand, wo ein Live-Query-Abonnement das Topic ist und ein Schreibvorgang in der Datenbank das Publizieren:
// JavaScript / Node.js — Back4app JS SDK
// Pub/sub at the edge: live queries subscribe, saves publish
// Subscriber — register interest in a topic
const topic = new Parse.Query('Event');
topic.equalTo('topic', 'orders');
const sub = await topic.subscribe();
sub.on('create', (event) => handle(event.get('payload')));
// Publisher — fire and forget; no knowledge of subscribers
const event = new Parse.Object('Event');
event.set('topic', 'orders');
event.set('payload', { orderId: 'o-1187', status: 'paid' });
await event.save(); // Flutter / Dart — Back4app Flutter SDK
// Pub/sub at the edge: live queries subscribe, saves publish
// Subscriber — register interest in a topic
final liveQuery = LiveQuery();
final topic = QueryBuilder<ParseObject>(ParseObject('Event'))
..whereEqualTo('topic', 'orders');
final sub = await liveQuery.client.subscribe(topic);
sub.on(LiveQueryEvent.create, (event) => handle(event.get('payload')));
// Publisher — fire and forget; no knowledge of subscribers
final event = ParseObject('Event')
..set('topic', 'orders')
..set('payload', {'orderId': 'o-1187', 'status': 'paid'});
await event.save(); // iOS / Swift — Back4app Swift SDK
// Pub/sub at the edge: live queries subscribe, saves publish
// Subscriber — register interest in a topic
let topic = Event.query("topic" == "orders")
let sub = try await topic.subscribe()
sub.handleEvent { _, e in
if case .created(let event) = e { handle(event.payload) }
}
// Publisher — fire and forget; no knowledge of subscribers
var event = Event()
event.topic = "orders"
event.payload = ["orderId": "o-1187", "status": "paid"]
try await event.save() // Android / Kotlin — Back4app Android SDK
// Pub/sub at the edge: live queries subscribe, saves publish
// Subscriber — register interest in a topic
val client = ParseLiveQueryClient.Factory.getClient()
val topic = ParseQuery.getQuery<ParseObject>("Event")
topic.whereEqualTo("topic", "orders")
val sub = client.subscribe(topic)
sub.handleEvent(SubscriptionHandling.Event.CREATE) { _, event ->
handle(event.getJSONObject("payload"))
}
// Publisher — fire and forget; no knowledge of subscribers
val event = ParseObject("Event")
event.put("topic", "orders")
event.put("payload", JSONObject(mapOf("orderId" to "o-1187", "status" to "paid")))
event.save() So funktioniert Pub/Sub
Der Broker erledigt vier Aufgaben: Publizierungen annehmen und sofort zurückkehren; jede Nachricht mit den Abonnements abgleichen (über den Topic-Namen, hierarchisch – orders.* – oder über Inhaltsattribute); je Subscriber eine eigenständige Kopie zustellen und dabei entsprechend der Garantiestufe wiederholen; und Nachrichten für Offline-Subscriber vorhalten, wo Dauerhaftigkeit konfiguriert ist – jene zeitliche Entkopplung, dank der ein mittags deployter Dienst nachholt, was er verpasst hat. Eine Vokabelnotiz, die ihren Satz wert ist: Die Nachricht ist der Umschlag; das Ereignis – “das ist passiert”, in der Vergangenheitsform – ist das, was Pub/Sub üblicherweise trägt, und ob es nur den Fakt oder den vollen Zustand trägt, ist Fowlers Unterscheidung zwischen Event Notification und Event-Carried State Transfer.
Pub/Sub vs. Message Queues vs. Observer-Muster
Die beiden Verwechslungen, in einer Tabelle geklärt:
| Pub/Sub | Message Queue | Observer | |
|---|---|---|---|
| Zustellung | Jeder Subscriber bekommt eine Kopie | Genau ein Worker konsumiert jede Nachricht | Subjekt ruft jeden Beobachter auf |
| Zweck | Ereignisse verteilen | Arbeit aufteilen | Im Prozess auf Zustand reagieren |
| Kopplung | Keine – über den Broker | Keine – über die Queue | Direkte Objektreferenzen |
| Zeitverhalten | Asynchron | Asynchron | Meist synchron |
| Grenze | Über Prozesse/Systeme hinweg | Über Worker hinweg | Innerhalb eines Prozesses |
| Kanonische Form | 1 Ereignis → N Reaktionen | N Jobs → M Worker | 1 Objekt → seine Listener |
Der Satz, der das Meeting überlebt: Eine Queue verteilt Arbeit; Pub/Sub vervielfältigt sie. Und Observer ist kein “kleines Pub/Sub” – genau die Indirektion des Brokers fehlt dem Observer, weshalb das Umbauen eines Observers zu Pub/Sub eine Architekturänderung ist und keine Umbenennung. In der Praxis bieten Broker beide Formen an: Consumer Groups machen aus einem Topic eine Queue pro Gruppe (das Markenzeichen von Kafka), Fanout-Exchanges machen aus einem Queue-System Pub/Sub.
Zustellgarantien: at-most-once vs. at-least-once vs. exactly-once
| Garantie | Fehlerverhalten | Kosten | Ihr Handler muss | Wählen Sie bei |
|---|---|---|---|---|
| At-most-once | Nachrichten können verschwinden | Am günstigsten, am schnellsten | Lücken vertragen | Flüchtigen Daten: Präsenz, Ticker, Metriken |
| At-least-once | Duplikate treffen ein | Acks + Wiederholungen | Idempotent sein | Fachlichen Ereignissen – der Standard |
| Exactly-once | Eingeschränkt, komplex | Dedup + Koordination | Trotzdem idempotent sein | Schmalen Pfaden, wo Broker es unterstützen |
Die QoS-Stufen 0/1/2 von MQTT entsprechen exakt diesen dreien – eine saubere Bestätigung, dass die Dreiteilung grundlegend ist und kein Anbietermarketing. Die Ingenieurswahrheit: Exactly-once von Ende zu Ende ist im Allgemeinen unerreichbar (das Zwei-Generäle-Problem in neuem Gewand); Systeme, die damit werben, kombinieren At-least-once-Zustellung mit Deduplizierung. Deshalb steht der eigentliche Vertrag des Musters in Ihrem Handler: At-least-once + Idempotenz – über eine Nachrichten-ID deduplizieren, Upserts mit dem Entitätsschlüssel verwenden oder vor dem Anwenden die Version prüfen – macht Duplikate von Fehlern zu wirkungslosen Operationen.
Reihenfolge, Dead Letters und Topic-Entwurf
Drei betriebliche Realitäten, die Einführungsdiagramme überspringen. Reihenfolge: Fan-out an parallele Konsumenten hat keine globale Ordnung; Broker stellen sie pro Partition oder Ordering Key wieder her, zum Preis der Parallelität – entwerfen Sie Handler so, dass sie Ereignisse nach Entitäts-ID und Version anwenden statt nach Eintreffreihenfolge, dann löst sich das Problem weitgehend auf. Giftige Nachrichten: Eine Nachricht, deren Verarbeitung immer eine Ausnahme wirft, wird unter At-least-once ewig wiederholt; begrenzen Sie die Zustellversuche und leiten Sie Fehlschläge zur Sichtung in eine Dead Letter Queue, sonst blockiert ein einziges schlechtes Ereignis das Topic. Topic-Entwurf: Benennen Sie hierarchisch (orders.paid, orders.refunded, Platzhalter orders.*), halten Sie die Granularität auf der Ebene, auf der sich Subscriber tatsächlich unterscheiden, und entwickeln Sie Nachrichtenschemas additiv weiter – Subscriber ignorieren unbekannte Felder; brechende Änderungen bekommen ein neues versioniertes Topic (orders.v2) mit Migrationsfenster, genau wie eine API-Version.
Typische Anwendungsfälle
- Microservice-Integration – Dienste verschiedener Teams reagieren auf die Ereignisse der anderen, ohne direkte Aufrufe und ohne gemeinsame Deployment-Termine.
- Echtzeit-Features auf Client-Seite – Chat-Fan-out, Live-Dashboards, Präsenz: Pub/Sub über WebSockets am Rand.
- IoT-Telemetrie – Tausende Geräte publizieren über MQTT; Konsumenten von der Alarmierung bis zur Auswertung abonnieren unabhängig.
- Cache-Invalidierung und Replikation – ein Schreibvorgang publiziert, jeder Cache und jedes Replikat benachrichtigt.
- Parallele Verarbeitungspipelines – ein Ereignis stößt Versand, Benachrichtigung und Analytics gleichzeitig an, jedes im eigenen Tempo.
Sollten Sie Pub/Sub verwenden? Eine Entscheidungsmatrix
| Pub/Sub passt, wenn … | Nehmen Sie etwas anderes, wenn … |
|---|---|
| Ein Ereignis mehrere unabhängige Konsumenten interessiert | Es nur einen Konsumenten gibt: eine Queue oder schlicht ein Aufruf |
| Produzenten und Konsumenten unabhängig deployen | Der Aufrufer die Antwort sofort braucht → Anfrage-Antwort |
| Eventual Consistency akzeptabel ist | Atomarität über alle Beteiligten nötig ist → Transaktionen/Saga |
| Subscriber im Lauf der Zeit kommen und gehen | Strikte globale Ordnung nicht verhandelbar ist |
| Stoßweise Last zwischen Systemen gepuffert werden muss | Das ganze System in einen Prozess passt → Observer |
Grenzen und Trade-offs
- Debugging führt über einen Broker. “Wer hat das konsumiert, und warum ist es fehlgeschlagen?” verlangt Korrelations-IDs und Tracing; dieselbe Entkopplung, die Teams befreit, verbirgt auch die Kausalität.
- Keine Antworten, so gewollt. Workflows, die Rückmeldungen brauchen, müssen sie als weitere Nachrichten modellieren – zusätzliche Latenz und Zustandsautomaten dort, wo früher ein Funktionsaufruf reichte.
- Der Broker ist Infrastruktur. Verfügbarkeit, Kapazität, Sicherheit und Aufbewahrungsrichtlinien der Messaging-Schicht werden zu Plattformarbeit; ein ausgefallener Broker multipliziert Störungen.
- Die Blindheit des Publishers schneidet in beide Richtungen. Publisher sehen den Gesundheitszustand der Subscriber nicht; ein stumm scheiternder Konsument verliert Daten, solange kein Monitoring der Dead Letters existiert.
- Garantien kosten Durchsatz. Ordering Keys serialisieren, Exactly-once koordiniert, Dauerhaftigkeit persistiert – jede Verschärfung der Semantik zahlt sich in Leistung; kaufen Sie nur, was die Daten brauchen.
Pub/Sub 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. Das Muster taucht hier am Client-Rand auf: Live Queries sind Pub/Sub, bei dem die Abfrage das Topic ist – Subscriber registrieren ein Prädikat, jeder passende Schreibvorgang wird über eine verwaltete WebSocket-Flotte an alle Subscriber publiziert, mit Berechtigungsprüfung pro Subscriber und Fan-out durch die Plattform, genau wie in den Code-Tabs oben. Serverseitige Reaktionen setzen sich genauso zusammen: Cloud-Code-Trigger abonnieren Datenänderungen (afterSave ist dem Geiste nach ein Topic-Abonnement), und geplante Funktionen arbeiten die als Zeilen publizierte Arbeit ab. Für schweres Streaming zwischen Diensten greifen Sie weiterhin zu einem dedizierten Broker wie Kafka oder RabbitMQ – für die üblichen Produktfälle jedoch liefert das Backend das Verteilen bei jeder Änderung bereits mit.
Häufige Fragen
Was ist Pub/Sub, einfach erklärt?
Ein Messaging-Muster, bei dem Sender (Publisher) Nachrichten in benannte Topics auf einem Broker stellen und jede Komponente, die dieses Topic abonniert hat, eine eigene Kopie erhält – Publisher und Subscriber erfahren nie voneinander. Denken Sie an Rundfunk: Der Sender strahlt auf einer Frequenz aus; wer einschaltet, hört mit.
Was ist der Unterschied zwischen Pub/Sub und einer Message Queue?
Eine Queue verteilt Arbeit, Pub/Sub vervielfältigt sie. In einer Queue konsumiert genau ein Worker jede Nachricht – das Werkzeug, um Jobs über einen Pool zu streuen. Bei Pub/Sub erhält jeder Subscriber des Topics eine Kopie – das Werkzeug, um Ereignisse an unabhängig Interessierte zu verteilen.
Was ist der Unterschied zwischen Pub/Sub und dem Observer-Muster?
Observer lebt im selben Prozess: Das Subjekt hält direkte Referenzen auf seine Beobachter und ruft sie meist synchron auf. Pub/Sub schiebt einen Broker zwischen die Beteiligten, entkoppelt sie damit vollständig, arbeitet typischerweise asynchron und erlaubt getrennte Prozesse, Sprachen und Deployments. Das eine ist ein Entwurfsmuster innerhalb einer App, das andere eine Architektur zwischen Systemen.
Was ist ein Topic bei Pub/Sub?
Ein benannter logischer Kanal, der Nachrichten kategorisiert: Publisher adressieren das Topic, und der Broker stellt jede Nachricht allen Subscribern dieses Topics zu. Gefiltert wird entweder topic-basiert (Abonnement über den Namen, oft hierarchisch – orders.*) oder inhaltsbasiert, wobei der Broker auf Nachrichtenattribute abgleicht.
Welche Zustellgarantien bietet Pub/Sub?
Drei Stufen. At-most-once: Fire-and-forget – schnell, kann Nachrichten verlieren. At-least-once: Wiederholung bis zur Bestätigung – der übliche Standard, erzeugt gelegentlich Duplikate. Exactly-once: Deduplizierung plus Koordination – teuer, eingeschränkt und im Allgemeinen Ende zu Ende nicht garantierbar. Die pragmatische Haltung: At-least-once-Zustellung mit idempotenten Handlern.
Garantiert Pub/Sub die Reihenfolge der Nachrichten?
Standardmäßig nicht – Nachrichten gehen im Fan-out an parallele Subscriber, und globale Ordnung arbeitet gegen Parallelität. Broker können innerhalb einer Partition oder eines Ordering Key sortieren, was Durchsatz kostet. Der robuste Entwurf setzt eine Reihenfolge nur dort voraus, wo sie explizit konfiguriert ist, und schreibt Handler, die unsortierte Ankunft vertragen.
Ist Kafka Pub/Sub?
Ja, mit einer Wendung: Apache Kafka setzt Publish-Subscribe-Semantik auf ein partitioniertes, dauerhaftes, wiederabspielbares Commit-Log. Innerhalb einer Consumer Group verhält es sich wie eine Queue (jede Nachricht an ein Mitglied), gruppenübergreifend wie Pub/Sub (jede Gruppe bekommt eine Kopie) – deshalb spricht man üblicherweise von Event Streaming.
Wann sollten Sie Pub/Sub nicht verwenden?
Wenn der Aufrufer eine sofortige Antwort braucht (Anfrage-Antwort), wenn Operationen über Produzent und Konsumenten hinweg atomar sein müssen (ein Broker kann an keiner Transaktion teilnehmen – siehe das Saga-Muster), wenn strikte globale Ordnung gefordert ist, oder wenn das System klein genug ist, dass ein Broker mehr Betriebsfläche hinzufügt als er beseitigt.