- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
- Event Sourcing speichert nicht den aktuellen Zustand, sondern jede Zustandsaenderung als unveraenderliches Event -- vollstaendige Audit-Historie inklusive
- Event Stores wie Kafka oder EventStoreDB laufen auf Kubernetes als StatefulSets mit persistentem Storage und garantierter Reihenfolge
- Projections (Read Models) werden aus dem Event Stream materialisiert und koennen jederzeit neu aufgebaut werden
- Snapshots verhindern, dass bei langen Event-Ketten die Wiederherstellung des aktuellen Zustands zu lange dauert
- CQRS + Event Sourcing trennt Schreib- und Lese-Seite konsequent -- ideal fuer skalierbare Microservices auf Kubernetes
Kubernetes Event Sourcing: Event-basierte Architektur fuer Microservices
In traditionellen Microservices speichert jeder Service seinen aktuellen Zustand in einer Datenbank. Eine Bestellung hat den Status "bezahlt" -- aber wie sie dorthin gekommen ist, ist verloren.
Event Sourcing dreht dieses Modell um: Statt den aktuellen Zustand zu speichern, wird jede Zustandsaenderung als unveraenderliches Event persistiert. Der aktuelle Zustand ergibt sich durch Abspielen aller Events.
Traditionell (State-basiert):
orders-db: { id: 42, status: "shipped", total: 99.90 }
Event Sourcing:
Event 1: OrderCreated { id: 42, items: [...], total: 109.90 }
Event 2: DiscountApplied { id: 42, discount: 10.00 }
Event 3: PaymentReceived { id: 42, amount: 99.90 }
Event 4: OrderShipped { id: 42, tracking: "DE123456" }
Der Vorteil: Jede Aenderung ist nachvollziehbar. Sie koennen den Zustand zu jedem beliebigen Zeitpunkt rekonstruieren und neue Auswertungen ueber historische Daten laufen lassen.
Wer sich mit event-basierten Mustern auf Kubernetes vertraut machen will: Kubernetes Saga Pattern behandelt verteilte Transaktionen ueber Microservices hinweg.
Kernkonzepte: Events, Streams und Aggregates
Ein Event beschreibt eine Zustandsaenderung, die bereits passiert ist. Events sind unveraenderlich (immutable), zeitlich geordnet und enthalten alle noetigem Informationen.
# Beispiel: OrderCreated Event
eventType: "OrderCreated"
eventId: "evt-2026-001"
streamId: "order-42"
timestamp: "2026-02-10T14:30:00Z"
version: 1
data:
orderId: "42"
customerId: "cust-789"
items:
- productId: "prod-100"
quantity: 2
price: 49.95
total: 99.90
metadata:
correlationId: "req-abc-123"
userId: "user-456"
Ein Event Stream gruppiert alle Events eines Aggregates. Das Aggregate ist die Konsistenzgrenze -- im Bestellsystem die einzelne Bestellung. Jedes Event hat eine Version fuer Optimistic Concurrency.
Event Store auf Kubernetes: Kafka vs EventStoreDB
Option 1: Apache Kafka als Event Store
Kafka ist primaer ein verteiltes Log-System, eignet sich aber auch als Event Store mit unbegrenzter Retention.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
namespace: event-sourcing
spec:
serviceName: kafka-headless
replicas: 3
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: confluentinc/cp-kafka:7.6.0
ports:
- containerPort: 9092
name: kafka
env:
- name: KAFKA_LOG_RETENTION_MS
value: "-1"
- name: KAFKA_LOG_RETENTION_BYTES
value: "-1"
volumeMounts:
- name: kafka-data
mountPath: /var/lib/kafka/data
resources:
requests:
cpu: "500m"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
volumeClaimTemplates:
- metadata:
name: kafka-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ssd-retain
resources:
requests:
storage: 100Gi
Wichtig: Retention auf unbegrenzt setzen (KAFKA_LOG_RETENTION_MS: "-1") -- ohne das loescht Kafka alte Events.
Option 2: EventStoreDB
EventStoreDB ist speziell fuer Event Sourcing gebaut und bietet native Unterstuetzung fuer Streams, Projektionen und Subscriptions.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: eventstoredb
namespace: event-sourcing
spec:
serviceName: eventstoredb-headless
replicas: 3
selector:
matchLabels:
app: eventstoredb
template:
metadata:
labels:
app: eventstoredb
spec:
containers:
- name: eventstoredb
image: eventstore/eventstore:24.2
ports:
- containerPort: 2113
name: http
env:
- name: EVENTSTORE_CLUSTER_SIZE
value: "3"
- name: EVENTSTORE_RUN_PROJECTIONS
value: "All"
volumeMounts:
- name: esdb-data
mountPath: /var/lib/eventstore
resources:
requests:
cpu: "500m"
memory: "1Gi"
volumeClaimTemplates:
- metadata:
name: esdb-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ssd-retain
resources:
requests:
storage: 50Gi
| Aspekt | Kafka | EventStoreDB |
|---|---|---|
| Projektionen | Extern (eigener Code) | Eingebaut (JavaScript) |
| Concurrency Control | Nicht nativ | Optimistic Concurrency |
| Skalierung | Horizontal (Partitions) | Cluster (3+ Nodes) |
| Betriebsaufwand | Hoch (ZooKeeper/KRaft) | Moderat |
Projections: Read Models aus Events aufbauen
Events sind optimal zum Schreiben, aber fuer Abfragen ungeeignet. Projections sind materialisierte Read Models, die aus dem Event Stream aufgebaut werden.
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-projection
namespace: event-sourcing
spec:
replicas: 1
selector:
matchLabels:
app: order-projection
template:
metadata:
labels:
app: order-projection
spec:
containers:
- name: projector
image: myregistry/order-projector:1.2.0
env:
- name: EVENT_STORE_URL
value: "eventstoredb-headless.event-sourcing.svc:2113"
- name: PROJECTION_DB_URL
valueFrom:
secretKeyRef:
name: projection-db-credentials
key: connection-string
Projections sind idempotent und wiederherstellbar. Wenn das Read Model korrupt ist, loeschen Sie es und bauen es aus dem Event Stream neu auf.
Fuer die zuverlaessige Event-Uebermittlung zwischen Services empfiehlt sich das Kubernetes Outbox Pattern.
Snapshots: Performance bei langen Event-Ketten
Ein Aggregate mit tausenden Events bei jedem Zugriff komplett neu aufzubauen ist ineffizient. Snapshots speichern den materialisierten Zustand zu einem bestimmten Zeitpunkt.
Ohne Snapshots:
Event 1 -> Event 2 -> ... -> Event 5000 -> Aktueller Zustand
(5000 Events abspielen = langsam)
Mit Snapshots:
Snapshot bei Event 4900 -> Event 4901 -> ... -> Event 5000
(Snapshot laden + 100 Events = schnell)
Wann Snapshots einsetzen: Aggregates mit mehr als 50-100 Events, latenz-sensitive Lese-Operationen, haeufig geladene Aggregates. Wann vermeiden: Aggregates mit wenigen Events (Overhead ueberwiegt).
CQRS + Event Sourcing: Die Kombination
CQRS trennt die Schreib-Seite (Commands) von der Lese-Seite (Queries). In Kombination mit Event Sourcing entsteht eine leistungsfaehige Architektur.
# Command-Seite: Nimmt Befehle entgegen, schreibt Events
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-command-service
namespace: event-sourcing
spec:
replicas: 2
selector:
matchLabels:
app: order-command
template:
metadata:
labels:
app: order-command
spec:
containers:
- name: command-handler
image: myregistry/order-command:2.1.0
ports:
- containerPort: 8080
env:
- name: EVENT_STORE_URL
value: "eventstoredb-headless.event-sourcing.svc:2113"
---
# Query-Seite: Liest aus dem materialisierten Read Model
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-query-service
namespace: event-sourcing
spec:
replicas: 3
selector:
matchLabels:
app: order-query
template:
metadata:
labels:
app: order-query
spec:
containers:
- name: query-handler
image: myregistry/order-query:2.1.0
ports:
- containerPort: 8081
env:
- name: READ_DB_URL
valueFrom:
secretKeyRef:
name: read-db-credentials
key: connection-string
Vorteile: Schreib- und Lese-Seite unabhaengig skalieren, multiple Read Models fuer verschiedene Abfrage-Muster, Event Store als Single Source of Truth.
Event Versioning: Schema-Evolution beherrschen
Events sind unveraenderlich -- aber Ihr Code entwickelt sich weiter. Drei Strategien fuer Schema-Evolution:
Strategie 1: Weak Schema -- Neue Felder hinzufuegen, Consumer prueft Version und nutzt Defaults.
# Version 1
eventType: "OrderCreated"
version: 1
data:
orderId: "42"
total: 99.90
# Version 2 (neues optionales Feld)
eventType: "OrderCreated"
version: 2
data:
orderId: "42"
total: 99.90
currency: "EUR"
Strategie 2: Upcasting -- Events werden beim Lesen in die aktuelle Version transformiert.
Strategie 3: Neue Event-Typen -- Bei grundlegenden Aenderungen einen neuen Typ einfuehren (OrderCreatedV2). Beide Typen koexistieren.
Best Practices: Felder nur hinzufuegen, nie entfernen. Schema Registry fuer Kafka-basierte Systeme nutzen. Kompatibilitaets-Tests in die CI/CD-Pipeline integrieren.
Monitoring fuer Event Sourcing
apiVersion: v1
kind: ConfigMap
metadata:
name: event-sourcing-alerts
namespace: event-sourcing
data:
alerts.yaml: |
groups:
- name: event-sourcing
rules:
- alert: ProjectionLagHigh
expr: event_sourcing_projection_lag_seconds > 30
for: 5m
labels:
severity: warning
- alert: EventStoreWriteLatencyHigh
expr: histogram_quantile(0.99, event_store_write_duration_seconds_bucket) > 0.5
for: 5m
labels:
severity: critical
Fuer die Trennung von Lese- und Schreibmodellen: CQRS Pattern auf Kubernetes.
Wann Event Sourcing einsetzen?
Gut geeignet: Systeme mit Audit-Anforderungen (Finanzen, Gesundheitswesen), Domains mit vielen Zustandsuebergaengen, temporale Queries, hohe Schreib-Raten mit verschiedenen Lese-Mustern.
Weniger geeignet: Einfache CRUD-Anwendungen, Prototypen und MVPs, Systeme ohne Audit-Anforderungen.
Fuer die Isolierung von Service-Daten: Database per Service Pattern.
Fazit
Event Sourcing auf Kubernetes kombiniert eine leistungsfaehige Architektur mit skalierbarer Infrastruktur. StatefulSets garantieren die Stabilitaet des Event Stores, Deployments skalieren Projections horizontal, und Kubernetes-native Monitoring-Tools ueberwachen Projection Lag und Schreib-Latenzen.
Beginnen Sie mit einem einzelnen Aggregate, implementieren Sie den Event Store (Kafka oder EventStoreDB), fuegen Sie eine Projection hinzu -- und erweitern Sie von dort. Fuer Resilience-Strategien in verteilten Systemen: Resilience Patterns auf Kubernetes.
Verwandte Artikel
- CQRS Pattern auf Kubernetes
- Saga Pattern auf Kubernetes
- Outbox Pattern auf Kubernetes
- Database per Service Pattern
- Resilience Patterns auf Kubernetes
Braucht ihr Unterstuetzung bei der Einfuehrung von Event Sourcing oder der Kafka-Architektur auf Kubernetes? Kontaktiert uns fuer eine individuelle Beratung.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
CQRS Pattern auf Kubernetes: Read/Write-Trennung umsetzen
CQRS Pattern auf Kubernetes umsetzen: Getrennte Read/Write-Services deployen, Event-driven Synchronisation mit Kafka und unabhängiges Scaling per HPA.
Kubernetes CQRS Pattern Microservices in Deutschland optimal nutzen
Optimieren Sie Skalierbarkeit und Performance Ihrer komplexen Microservices auf Kubernetes in Deutschland mit dem CQRS Pattern. Erfahren Sie, wie diese zukunftsweisende Architektur Compliance-Anforderungen erfüllt und digitale Souveränität für deutsche Unternehmen sichert.
Database per Service: Datenbank-Strategien auf Kubernetes
Database per Service vs Shared Database auf Kubernetes: Daten-Isolation, Eventual Consistency, CQRS und StatefulSets mit YAML-Beispielen.
Outbox Pattern auf Kubernetes mit Debezium und Kafka
Transactional Outbox auf Kubernetes umsetzen: CDC mit Debezium, Kafka Connect Integration und produktionsreife YAML-Beispiele für Microservices.
Distributed Tracing: Jaeger auf Kubernetes einrichten
Jaeger für Distributed Tracing auf Kubernetes einrichten mit dem Jaeger Operator. OpenTelemetry-Instrumentation in Go und Python, Trace-Propagation zwischen Microservices und praktische Analyse von Latenz-Problemen.