Veröffentlicht am

Saga Pattern auf Kubernetes: Verteilte Transaktionen

Teilen:
Authors

TL;DR

  • Saga Pattern ersetzt verteilte Two-Phase-Commits durch eine Kette lokaler Transaktionen mit definierten Kompensations-Aktionen bei Fehlern
  • Choreography laesst Services selbststaendig auf Events reagieren -- einfach bei wenigen Services, schwer nachvollziehbar bei komplexen Ablaeufen
  • Orchestration nutzt einen zentralen Saga-Koordinator, der den Ablauf steuert -- besser fuer komplexe Workflows mit vielen Schritten
  • Jeder Schritt braucht eine Kompensation: Bestellung stornieren, Zahlung zurueckbuchen, Reservierung aufheben -- diese muessen idempotent sein
  • Auf Kubernetes lassen sich Sagas mit Event-Brokern (Kafka), Workflow-Engines (Temporal) oder Dapr Building Blocks umsetzen

Kubernetes Saga Pattern: Verteilte Transaktionen fuer Microservices

In einer monolithischen Anwendung laeuft eine Bestellung in einer einzigen Datenbank-Transaktion: Bestellung anlegen, Zahlung buchen, Versand ausloesen -- alles atomar, alles konsistent. Schlaegt ein Schritt fehl, macht ein Rollback alles rueckgaengig.

In einer Microservices-Architektur auf Kubernetes hat jeder Service seine eigene Datenbank. Ein Two-Phase-Commit ueber Service-Grenzen hinweg ist in der Praxis nicht tragbar: Er blockiert Ressourcen, skaliert nicht und fuehrt bei Netzwerkpartitionen zu undefinierten Zustaenden.

Das Saga Pattern loest dieses Problem durch eine Sequenz lokaler Transaktionen. Jeder Service fuehrt seine lokale Transaktion aus und publiziert ein Event. Bei einem Fehler werden bereits abgeschlossene Schritte durch Kompensations-Aktionen rueckgaengig gemacht.

Wer die Grundlagen von Microservices-Kommunikation auf Kubernetes vertiefen will: Kubernetes Dapr: Sidecar-Pattern fuer Microservices.


Das Problem: Verteilte Transaktionen

Bestellvorgang (3 Services, 3 Datenbanken):

1. Order Service    */} Bestellung anlegen (orders-db)
2. Payment Service  */} Zahlung buchen (payments-db)
3. Shipping Service */} Versand beauftragen (shipping-db)

Ohne Saga: Schlaegt der Shipping Service fehl, bleiben Bestellung und Zahlung bestehen. Der Kunde wurde belastet, erhaelt aber keine Ware. Mit Saga: Der Fehler loest Kompensationen aus -- Payment bucht zurueck, Order storniert. Das System kehrt in einen konsistenten Zustand zurueck.


Variante 1: Choreography-basierte Saga

Bei der Choreography reagiert jeder Service eigenstaendig auf Events. Es gibt keinen zentralen Koordinator.

Fehlerfall mit Kompensation

Order Service        Payment Service       Shipping Service
     |                     |                      |
     |-- OrderCreated --*/}|                      |
     |                     |-- PaymentCompleted ->|
     |                     |                      |-- ShippingFailed!
     |                     |<- CompensatePayment -|
     |<- CompensateOrder --|                      |
     |                     |                      |
  (Order storniert)  (Zahlung zurueckgebucht)     |

Order Service Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: shop
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
        saga-role: participant
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:v2.4.0
          ports:
            - containerPort: 8080
          env:
            - name: KAFKA_BROKERS
              value: "kafka-0.kafka.shop.svc.cluster.local:9092"
            - name: KAFKA_TOPIC_ORDERS
              value: "saga.orders"
            - name: KAFKA_CONSUMER_GROUP
              value: "order-service-saga"
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /healthz/ready
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5

Fuer Health Checks und Probes in der Praxis: Kubernetes Health Checks und Probes.

Choreography: Vor- und Nachteile

AspektBewertung
EntkopplungHoch -- Services kennen nur Events, nicht andere Services
EinfachheitGut bei 2-4 Services, schlecht bei 5+
NachvollziehbarkeitSchwierig -- verteilte Logik, kein zentraler Ueberblick
FehlerbehandlungJeder Service muss Kompensation selbst implementieren

Variante 2: Orchestration-basierte Saga

Ein zentraler Saga Orchestrator steuert den Ablauf. Er ruft Services in der definierten Reihenfolge auf und loest bei Fehlern die Kompensationen in umgekehrter Reihenfolge aus.

Ablauf mit Orchestrator

Saga Orchestrator
     |
     |--1. CreateOrder -------*/} Order Service
     |<--- OrderCreated ---------|
     |
     |--2. ProcessPayment ----*/} Payment Service
     |<--- PaymentCompleted ------|
     |
     |--3. ArrangeShipping ---*/} Shipping Service
     |<--- ShippingFailed! ------|
     |
     |--4. CompensatePayment -*/} Payment Service   (Kompensation)
     |--5. CompensateOrder ---*/} Order Service      (Kompensation)
     |
     Saga Status: COMPENSATED

Saga Orchestrator Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: saga-orchestrator
  namespace: shop
spec:
  replicas: 2
  selector:
    matchLabels:
      app: saga-orchestrator
  template:
    metadata:
      labels:
        app: saga-orchestrator
    spec:
      containers:
        - name: orchestrator
          image: registry.example.com/saga-orchestrator:v1.2.0
          ports:
            - containerPort: 8080
          env:
            - name: KAFKA_BROKERS
              value: "kafka-0.kafka.shop.svc.cluster.local:9092"
            - name: SAGA_STATE_STORE
              value: "redis-master.shop.svc.cluster.local:6379"
            - name: SAGA_TIMEOUT_SECONDS
              value: "30"
            - name: SAGA_RETRY_MAX
              value: "3"
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi

Saga Definition als ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: order-saga-definition
  namespace: shop
data:
  order-saga.yaml: |
    saga: order-processing
    version: v1
    steps:
      - name: create-order
        service: order-service
        action: /api/orders
        compensation: /api/orders/{orderId}/cancel
        timeout: 10s
      - name: process-payment
        service: payment-service
        action: /api/payments
        compensation: /api/payments/{paymentId}/refund
        timeout: 15s
      - name: arrange-shipping
        service: shipping-service
        action: /api/shipments
        compensation: /api/shipments/{shipmentId}/cancel
        timeout: 10s
    on_failure: compensate_all
    on_timeout: compensate_all

Kompensations-Logik: Die Rueckwaerts-Kette

Kompensationen sind das Herzstrueck jeder Saga. Sie muessen drei Eigenschaften erfuellen:

1. Idempotenz

Eine Kompensation darf mehrfach ausgefuehrt werden und muss immer das gleiche Ergebnis liefern. Bei Netzwerk-Timeouts wird die Kompensation erneut gesendet. Der Payment Service prueft vor jedem Refund, ob die Zahlung bereits zurueckgebucht wurde.

2. Retries mit Backoff

apiVersion: v1
kind: ConfigMap
metadata:
  name: saga-retry-config
  namespace: shop
data:
  retry-policy.yaml: |
    compensation:
      max_retries: 5
      initial_delay: 1s
      max_delay: 30s
      backoff_multiplier: 2
      retryable_errors:
        - TIMEOUT
        - SERVICE_UNAVAILABLE
      non_retryable_errors:
        - INVALID_REQUEST
        - NOT_FOUND

3. Saga-Status Tracking

Jede Saga durchlaeuft definierte Zustaende: STARTED, STEP_PENDING, STEP_COMPLETED, COMPENSATING, COMPENSATED, COMPLETED oder FAILED. Der Status wird im Redis State Store persistiert und ist jederzeit abfragbar.


Choreography vs. Orchestration: Entscheidungsmatrix

KriteriumChoreographyOrchestration
Anzahl Services2-4 Services optimal5+ Services optimal
Team-StrukturAutonome TeamsZentrales Platform-Team
AenderungshaeufigkeitSelten neue SchritteHaeufig neue Schritte
DebuggingDistributed Tracing noetigZentrales Saga-Log
LatenzNiedriger (kein Hop ueber Orchestrator)Hoeher (zusaetzlicher Hop)
VerfuegbarkeitKein Single Point of FailureOrchestrator muss HA sein

Fuer die Wahl der richtigen Deployment-Strategie der Saga-Services: Kubernetes Deployment Strategien.


Monitoring und Observability

Saga-spezifische Metriken

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: saga-orchestrator-monitor
  namespace: shop
spec:
  selector:
    matchLabels:
      app: saga-orchestrator
  endpoints:
    - port: metrics
      interval: 15s
      path: /metrics
MetrikBeschreibungAlert-Schwelle
saga_totalGesamtzahl gestarteter SagasBaseline
saga_compensatedSagas mit KompensationRate ueber 5%
saga_failedFehlgeschlagene Sagas (inkl. Kompensation)Jeder Einzelfall
saga_duration_secondsDauer einer Saga End-to-Endp99 ueber 30s

Saga Pattern mit Temporal auf Kubernetes

Temporal ist eine Workflow-Engine, die Saga-Orchestration nativ unterstuetzt. Workflows sind als Code definiert, Retries und Kompensationen sind eingebaut.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: temporal-worker
  namespace: shop
spec:
  replicas: 3
  selector:
    matchLabels:
      app: temporal-worker
  template:
    metadata:
      labels:
        app: temporal-worker
    spec:
      containers:
        - name: worker
          image: registry.example.com/saga-worker:v1.0.0
          env:
            - name: TEMPORAL_HOST
              value: "temporal-frontend.temporal.svc.cluster.local:7233"
            - name: TEMPORAL_NAMESPACE
              value: "shop-sagas"
            - name: TEMPORAL_TASK_QUEUE
              value: "order-saga-queue"
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi

Temporal bietet gegenueber einer Eigenentwicklung: automatische Retries, Saga-Kompensation als Workflow-Primitive, Visibility API fuer den Status aller laufenden Sagas, und Versioning fuer Workflow-Updates ohne Downtime.

Fuer event-basierte Skalierung der Saga-Teilnehmer: Kubernetes KEDA Autoscaling.


Best Practices

  1. Kompensationen immer idempotent implementieren: Netzwerk-Fehler fuehren zu Retries. Eine doppelt ausgefuehrte Kompensation darf keine Seiteneffekte haben.
  2. Timeouts definieren: Jeder Saga-Schritt braucht ein Timeout. Ohne Timeout haengen Sagas ewig im Status STEP_PENDING.
  3. Dead Letter Queues einrichten: Events, die nach allen Retries nicht verarbeitet werden koennen, landen in einer DLQ fuer manuelle Analyse.
  4. Saga-ID durch alle Services propagieren: Eine eindeutige Saga-ID erleichtert Tracing und Debugging ueber Service-Grenzen hinweg.
  5. Events versionieren: Schema-Aenderungen an Saga-Events muessen rueckwaertskompatibel sein.

Verwandte Artikel


Sie implementieren verteilte Transaktionen in Ihrer Microservices-Architektur oder planen die Migration von einem Monolithen? Wir unterstuetzen Sie bei der Wahl des richtigen Saga-Patterns, der Kompensations-Logik und dem produktiven Betrieb auf Kubernetes. Kontaktieren Sie uns unter /kontakt.

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