Zurück zum Blog
5 min

Pub/Sub oder Eventarc? Event-Driven GCP ohne Spaghetti

Wann Pub/Sub, wann Eventarc — und wie du ein event-driven GCP-System sauber hältst: Idempotenz, Dead-Letter-Queues und die Falle des Fan-out-Spaghetti.

event-driven
Teil vonArchitektur →
Inhalt

Das erste event-driven System fühlt sich wie Magie an: eine Datei landet im Bucket, eine Function feuert, ein Datensatz erscheint. Das zehnte fühlt sich wie ein Tatort an. Niemand weiß, was was auslöst, ein Duplikat hat gerade einen Kunden doppelt belastet, und eine schlechte Nachricht wiederholt sich seit Dienstag.

Event-driven auf GCP ist nicht schwer, weil die Tools schwach wären. Es entgleist, weil zwei ähnlich aussehende Dienste — Pub/Sub und Eventarc — austauschbar genutzt werden und die langweiligen Teile (Idempotenz, Dead-Letter) übersprungen werden, bis die Produktion sie lehrt.

Wenn die Datei landet, die Function feuert und niemand erklären kann, warum.

Das ist der Feldführer: zu welchem du greifst, wie du Handler sicher hältst und wie du verhinderst, dass der Fan-out zu Spaghetti wird.

Pub/Sub vs Eventarc: einer transportiert, einer routet

Sie überlappen, also wird aus Gewohnheit gewählt. Die saubere Regel:

  • Pub/Sub ist das Messaging-Rückgrat. Du publizierst Events, die dir gehören, in ein Topic; Consumer abonnieren. Du kontrollierst Schema, Ordering, Retention. Nutze es für eigene Domain-Events — order.placed, payment.settled.
  • Eventarc ist ein Router darüber. Es nimmt Events, die Google bereits aussendet — Cloud-Storage-Uploads, Audit Logs, 90+ Quellen — und liefert sie als einen CloudEvents-Vertrag an ein Ziel. Nutze es, um auf die Plattform zu reagieren, ohne Glue zu schreiben.

Selten wählst du eines gegen das andere; Eventarc reitet ohnehin auf Pub/Sub. Die Frage ist „wer erzeugt dieses Event?“. Bist du es, Pub/Sub. Ist es Google, Eventarc.

Event-driven GCP auf einen Blick: Google sendet an Eventarc, du publizierst an Pub/Sub, Fan-out zu idempotenten Subscribern, Dead-Letter für das Gift.

Terminal window
# Eigenes Event → Pub/Sub
gcloud pubsub topics create order-placed
gcloud pubsub subscriptions create fulfilment --topic=order-placed
# Ein GCP-Event (Datei hochgeladen) → Eventarc, kein Glue-Code
gcloud eventarc triggers create on-upload \
--destination-run-service=thumbnailer \
--event-filters="type=google.cloud.storage.object.v1.finalized" \
--event-filters="bucket=my-uploads"

At-least-once heißt: es kommt zweimal an

Beide liefern at-least-once. Das ist kein Sonderfall — plane dafür. Ein Retry, ein langsames Ack, ein Redeploy mittendrin, und dasselbe Event landet erneut. Wenn „zweimal“ eine Doppelbelastung bedeutet, ist das ein Bug, den du geschrieben hast, kein Pech.

Mache jeden Consumer idempotent: dedupliziere über eine stabile Event-ID, dann wird ein Re-Run zum No-op.

def handle(event):
eid = event["id"] # stabil, von Pub/Sub/Eventarc geliefert
if seen.add_if_absent(eid): # atomar: False, wenn schon vorhanden
process(event) # echte Arbeit genau einmal
# Duplikat → still acken, kein Seiteneffekt

Der Store kann Redis mit TTL, eine Unique-Spalte oder Firestore sein. Die Regel bleibt: die zweite Kopie tut nichts.

Dead-Letter: eine Gift-Nachricht darf nicht alles stoppen

Ein einzelner unparsbarer Payload wiederholt sich ewig und blockiert die Schlange dahinter. Ein Dead-Letter-Topic parkt ihn nach N Versuchen, damit echter Traffic weiterläuft.

Terminal window
gcloud pubsub subscriptions update fulfilment \
--dead-letter-topic=fulfilment-dead \
--max-delivery-attempts=5

Dann alarmiere auf dem Dead-Letter-Topic. Eine Nachricht dort ist eine zu beantwortende Frage, kein Rauschen — aber der Rest des Flows stockt nie.

Push oder Pull: wie Subscriber ihre Events bekommen

Vor der Topologie: das Liefermodell richtig wählen. Eine Pub/Sub-Subscription ist entweder Push oder Pull, und Einsteiger wählen falsch und kämpfen dann gegen die Plattform:

  • Push — Pub/Sub POSTet jede Nachricht an einen HTTPS-Endpoint (Cloud Run, Function). Kein Polling, skaliert auf null, ideal für Serverless. Der Endpoint muss schnell mit 2xx acken.
  • Pull — dein Worker holt Batches und ackt sie. Am besten für Hochdurchsatz-Backends, lange Jobs oder feine Concurrency-Kontrolle.

Faustregel: Serverless-Ziel → Push; Dauer-Worker → Pull. Eventarc zu Cloud Run ist intern Push — du wählst nicht, und das ist gut so.

Ordering: meist willst du es nicht

Pub/Sub kann Reihenfolge innerhalb eines Ordering-Keys halten, aber Ordering drosselt Durchsatz und die meisten Flows brauchen es nicht. Baue Consumer so, dass die Ankunftsreihenfolge egal ist: order.placed dann order.cancelled muss in jeder Reihenfolge korrekt sein. Aktiviere Ordering-Keys nur, wenn State wirklich von Sequenz abhängt (Konto-Ledger), und keye pro Entität, nie global.

Terminal window
gcloud pubsub topics publish order-events --message="..." --ordering-key="acct-42"

Publiziere einen Fakt, kein Blob

Ein Topic ist ein Vertrag. Events sollten versioniert, selbstbeschreibend und klein sein — IDs, keine ganzen Datensätze. Trage type, eine stabile id und ein v, damit Consumer ohne Koordination wachsen:

{ "id": "evt_9f3", "type": "order.placed", "v": 1, "orderId": "A42", "ts": "2026-06-29T10:00:00Z" }

Fette Payloads koppeln Producer und Consumer; die ID lässt jeden Subscriber genau holen, was er braucht. Felder frei ergänzen, nie brechen oder umbenennen — stattdessen v erhöhen.

Wann NICHT event-driven

Events sind nicht gratis, und die schlimmste Spaghetti ist async, wo sync genügt. Greife zu einem direkten Call oder Cloud Tasks, wenn:

  • Du jetzt ein Ergebnis brauchst — eine synchrone Anfrage, kein Broadcast.
  • Ein bekannter Producer, ein bekannter Consumer — das ist eine Queue; nimm Cloud Tasks mit Retries und Rate-Limits, kein Topic.
  • Ein Zwei-Schritt-Flow — ein direkter Call schlägt ein Topic, das niemand sonst abonniert.

Nutze Pub/Sub, wenn viele Consumer denselben Fakt brauchen und Producer nicht wissen dürfen, wer lauscht. Tut es nur einer, hast du Spaghetti umsonst gekauft.

Die Spaghetti: hör auf, Trigger blind zu verketten

Das echte Chaos sind nicht die Tools — es ist die Topologie. A feuert B, B feuert C, C feuert leise wieder A, und niemand hat die Karte gezeichnet. Drei Regeln halten es flach:

  1. Topic = Fakt, nicht Befehl. Publiziere order.placed, nicht send.email. Producer sagen, was geschah; Consumer entscheiden, was zu tun ist. Neues Verhalten = neuer Subscriber, null Producer-Änderungen.
  2. Fan-out statt Kette. Viele Subscriber an einem Topic schlagen ein 6-Hop-Relay. Parallele Pfade sind debugbar; Ketten verstecken Zyklen.
  3. Eine Routing-Quelle. Halte Trigger in Terraform, nicht im Klick. Lebt der Graph nur im Kopf, ist es schon Spaghetti.

Die Feldregel

Pub/Sub, wenn du das Event erzeugst, Eventarc, wenn Google es tut. Nimm an, jedes Event kommt zweimal, und mache Handler idempotent. Dead-letter das Gift, damit eine schlechte Nachricht die Linie nicht stoppt. Publiziere Fakten, mach Fan-out statt Kette und halte Routing im Code. Das richtig gemacht, bleibt event-driven die Magie von Tag eins — statt zum Tatort von Artikel zehn zu werden.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Pub/Sub und Eventarc?

Pub/Sub ist das rohe Messaging-Rückgrat — du publizierst und abonnierst Topics und besitzt das Routing. Eventarc sitzt darauf und leitet fertige Events von Google-Diensten (Cloud Storage, Audit Logs, 90+ Quellen) mit einem CloudEvents-Vertrag an ein Ziel. Greife zu Pub/Sub, wenn du eigene Events erzeugst; greife zu Eventarc, wenn du auf Events reagierst, die Google bereits aussendet.

Brauche ich Pub/Sub noch, wenn ich Eventarc nutze?

Fast immer ja — Eventarc nutzt für die meisten Pfade intern Pub/Sub und gibt dir ohnehin ein verwaltetes Topic. Es ist kein Entweder-oder: Eventarc ist die Routing-Schicht, Pub/Sub der Transport. Du wählst Eventarc, um Glue zwischen Quelle und Ziel zu sparen, und bekommst dennoch ein Pub/Sub-Topic für zusätzliche Subscriber.

Warum brauche ich idempotente Consumer?

Pub/Sub und Eventarc liefern at-least-once, dasselbe Event kann also zweimal ankommen. Wenn ein Duplikat eine Karte doppelt belastet oder zwei Mails sendet, ist das ein Bug, kein Pech. Mache Handler idempotent — dedupliziere über eine stabile Event-ID und behandle einen Re-Run als No-op — dann ist Redelivery harmlos statt gefährlich.

Was ist eine Dead-Letter-Queue und wann brauche ich sie?

Ein Dead-Letter-Topic fängt Nachrichten, die nach N Versuchen fehlschlagen, damit ein einzelnes Gift-Event nicht die ganze Subscription blockiert. Du brauchst es, sobald eine festsitzende Nachricht echten Traffic stauen kann. Ohne sie wiederholt ein unparsbarer Payload endlos; mit ihr parkt das schlechte Event beiseite und der Rest läuft weiter.

Push- oder Pull-Subscription?

Push, wenn dein Ziel serverless ist — Pub/Sub POSTet jede Nachricht an einen Cloud-Run- oder Function-Endpoint, also kein Polling und Skalierung auf null. Pull, wenn du einen Dauer-Worker mit hohem Durchsatz oder feiner Concurrency-Kontrolle betreibst. Eventarc zu Cloud Run ist intern Push, du wählst also meist gar nicht.

War dieser Artikel hilfreich?