Cloud allgemein

Cloud-Native ETL-Patterns für moderne Data-Platforms

Battle-tested ETL-Patterns für cloud-native Data-Platforms — Streaming-Ingestion, Schema-Evolution, Idempotent-Loads, Orchestration mit Terraform und YAML.

Harbinger Team3. April 20266 Min. LesezeitAktualisiert 14.5.2026
  • etl
  • data-engineering
  • cloud-native
  • streaming
  • terraform
  • airflow
Inhaltsverzeichnis21 Abschnitte

Cloud-Native ETL-Patterns für moderne Data-Platforms

TL;DR

  • Cloud-Native-ETL: Stateless-Compute, Event-driven-Triggers, Managed-Infra, Schema-aware, Idempotent by Default.
  • Sechs Production-Patterns: Medallion (Bronze/Silver/Gold), CDC, Schema-Evolution, Idempotent-Loads, Event-driven Orchestration, DLQ.
  • Start mit Medallion als Foundation, CDC für OLTP-Sources, Idempotenz von Tag 1. Add Observability auf jedem Layer.
  • Schema-Drift ist First-Class-Concern — Schema-Registry, Delta-Auto-Merge oder manual Migration je nach Evolution-Type.

Moderne Data-Platforms haben sich von der Nightly-Batch-Window wegbewegt. Heutige Architekturen werden erwartet, fresh, reliable und schema-resiliente Pipelines zu liefern, die automatisch skalieren, graceful failen und proportional zur Nutzung kosten. Cloud-Native-ETL ist kein Nice-to-have mehr — Baseline.

Dieser Artikel covert die Patterns, die brittle Legacy-Pipelines von Production-grade, cloud-native Data-Platforms trennen.


Was "Cloud-Native ETL" tatsächlich bedeutet

Cloud-Native-ETL ist nicht "deine SSIS-Packages auf einer VM in AWS laufen lassen". Es ist ein Set Design-Principles:

  • Stateless Compute: Worker halten keinen State zwischen Runs
  • Event-driven Triggers: Pipelines reagieren auf Daten-Arrival, nicht Uhren
  • Managed Infrastructure: Kein Kafka-Cluster-Patchen um 2 Uhr
  • Schema-aware: Pipelines evolvieren mit deinem Daten-Model, nicht dagegen
  • Idempotent by Default: Re-Run produziert selbes Result
graph LR
    A[Source Systems] -->|CDC / Events| B[Streaming Ingestion Layer]
    B --> C[Raw Landing Zone]
    C --> D[Schema Registry]
    D --> E[Transform Layer]
    E --> F[Serving Layer]
    F --> G[BI / ML / APIs]
    H[Orchestrator] -.->|trigger| B
    H -.->|trigger| E

Pattern 1: Die Medallion-Architecture

Das am weitesten adoptierte Pattern in modernen Lakehouses. Daten fließen durch Bronze → Silver → Gold-Layer, jeder mit erhöhten Quality-Guarantees.

LayerZweckFormatUpdate-Frequency
BronzeRaw-Ingestion, keine TransformationParquet / DeltaNear-Real-Time
SilverCleaned, dedupliziert, typedDelta15-60 min
GoldBusiness-ready AggregatesDelta / IcebergStündlich / Täglich

Terraform: S3-Bucket-Struktur für Medallion

resource "aws_s3_bucket" "data_lake" {
  for_each = toset(["bronze", "silver", "gold"])
  bucket   = "my-platform-${each.key}-${var.environment}"

  tags = {
    Layer       = each.key
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_s3_bucket_versioning" "data_lake_versioning" {
  for_each = aws_s3_bucket.data_lake
  bucket   = each.value.id

  versioning_configuration {
    status = "Enabled"
  }
}

Pattern 2: Change Data Capture (CDC) Ingestion

Source-DBs zu pollen zerstört sie. CDC tailed das Transaction-Log und captured Inserts, Updates, Deletes als Event-Stream mit zero Load auf Source.

Debezium + Kafka: Core-Config

# debezium-postgres-connector.yaml
name: postgres-cdc-connector
config:
  connector.class: io.debezium.connector.postgresql.PostgresConnector
  database.hostname: prod-postgres.internal
  database.port: "5432"
  database.user: debezium_reader
  database.password: "${secrets.pg_password}"
  database.dbname: transactions
  database.server.name: prod_pg
  table.include.list: public.orders,public.customers,public.payments
  plugin.name: pgoutput
  publication.autocreate.mode: filtered
  slot.name: debezium_slot
  topic.prefix: cdc
  decimal.handling.mode: double
  heartbeat.interval.ms: "5000"

CDC-Events Downstream handhaben

CDC produziert drei Event-Types: c (create), u (update), d (delete). Deine Landing-Logic muss alle drei handhaben:

# Spark-Structured-Streaming-Job-Config
spark:
  app.name: cdc-bronze-landing
  streaming:
    trigger: processingTime=30 seconds
    checkpointLocation: s3://my-platform-bronze/checkpoints/cdc/
    outputMode: append
  kafka:
    bootstrap.servers: kafka-broker-1:9092,kafka-broker-2:9092
    subscribe: cdc.public.orders,cdc.public.customers
    startingOffsets: latest
    failOnDataLoss: "false"

Pattern 3: Schema-Evolution ohne Pipelines zu brechen

Schema-Drift ist der stille Killer von ETL-Pipelines. Source-System addet eine Column — deine Pipeline bricht. Fix: Pipelines schema-aware von Tag 1.

Strategy 1: Schema-Registry (Apache Avro)

# Schema mit Confluent-Schema-Registry registrieren
curl -X POST http://schema-registry:8081/subjects/orders-value/versions   -H "Content-Type: application/vnd.schemaregistry.v1+json"   -d '{
    "schema": "{"type":"record","name":"Order","fields":[{"name":"id","type":"string"},{"name":"amount","type":"double"},{"name":"currency","type":["null","string"],"default":null}]}"
  }'

# Compatibility checken bevor Schema-Change deployen
curl -X POST http://schema-registry:8081/compatibility/subjects/orders-value/versions/latest   -H "Content-Type: application/vnd.schemaregistry.v1+json"   -d @new_schema.json

Strategy 2: Delta-Lake-Schema-Evolution

# Auto-Schema-Merging in Delta-Lake enablen
spark.conf.set("spark.databricks.delta.schema.autoMerge.enabled", "true")

# Write mit mergeSchema-Option
df.write \
  .format("delta") \
  .mode("append") \
  .option("mergeSchema", "true") \
  .save("s3://my-platform-silver/orders/")
Evolution-TypeSchema-RegistryDelta-Auto-MergeManuelle Migration
Add Nullable ColumnBACKWARD-CompatAutoJa
Remove ColumnNur FULL-CompatFailedManuell
Type-ChangeBreakingFailedManuell
Add Required ColumnBreakingFailedManuell

Pattern 4: Idempotent Loads

Re-runnable Pipelines sind safe Pipelines. Jeder Load sollte selbes Result produzieren, ob er einmal oder zehnmal läuft.

UPSERT-Pattern mit MERGE

-- Delta-Lake-MERGE für Idempotent-Upserts
MERGE INTO silver.orders AS target
USING (
  SELECT * FROM bronze.orders_staging
  WHERE _ingestion_date = current_date()
) AS source
ON target.order_id = source.order_id
WHEN MATCHED AND source.updated_at > target.updated_at THEN
  UPDATE SET *
WHEN NOT MATCHED THEN
  INSERT *;

Partition-Replace-Pattern

Für große Historical-Loads, replace entire Partitions atomic:

# Spark: nur spezifische Partitions overwriten
spark.conf.set("spark.sql.sources.partitionOverwriteMode", "dynamic")

df.write \
  .format("delta") \
  .mode("overwrite") \
  .partitionBy("year", "month", "day") \
  .save("s3://my-platform-silver/events/")

Pattern 5: Event-Driven Orchestration

Cron-basierte Pipelines verschwenden Resources und führen Arbitrary-Latency ein. Event-driven-Triggers feuern wenn Daten ankommen.

Airflow mit S3-Sensor

# dag_config.yaml
dag_id: bronze_to_silver_orders
schedule_interval: null  # Event-driven only
default_args:
  owner: data-platform
  retries: 3
  retry_delay_minutes: 5
  email_on_failure: true

tasks:
  - id: wait_for_cdc_landing
    type: S3KeySensor
    bucket: my-platform-bronze
    prefix: orders/year={{ ds_nodash[:4] }}/
    poke_interval: 60
    timeout: 3600

  - id: run_silver_transform
    type: DatabricksRunNowOperator
    depends_on: [wait_for_cdc_landing]
    job_id: "{{ var.value.silver_orders_job_id }}"

Terraform: EventBridge-Rule für S3-Triggered-Lambda

resource "aws_cloudwatch_event_rule" "s3_landing_trigger" {
  name        = "bronze-landing-trigger"
  description = "Trigger ETL pipeline on new S3 objects"

  event_pattern = jsonencode({
    source      = ["aws.s3"]
    detail-type = ["Object Created"]
    detail = {
      bucket = {
        name = [aws_s3_bucket.data_lake["bronze"].id]
      }
      object = {
        key = [{ prefix = "orders/" }]
      }
    }
  })
}

resource "aws_cloudwatch_event_target" "trigger_step_function" {
  rule      = aws_cloudwatch_event_rule.s3_landing_trigger.name
  target_id = "TriggerEtlStateMachine"
  arn       = aws_sfn_state_machine.etl_pipeline.arn
  role_arn  = aws_iam_role.eventbridge_sfn_role.arn
}

Pattern 6: Dead-Letter-Queues für Failed Records

Drop niemals Records silently. Failed Rows sollten in DLQ landen für Inspection und Replay.

# Kafka-DLQ-Config für deinen Consumer
spring:
  kafka:
    consumer:
      group-id: etl-silver-transform
      auto-offset-reset: earliest
    listener:
      ack-mode: manual
  cloud:
    stream:
      bindings:
        input:
          destination: cdc.public.orders
          group: etl-silver-transform
          consumer:
            max-attempts: 3
            back-off-initial-interval: 1000
            back-off-multiplier: 2.0
      rabbit:
        bindings:
          input:
            consumer:
              auto-bind-dlq: true
              dlq-ttl: 604800000  # 7 Tage

Observability für ETL-Pipelines

Du kannst nicht managen, was du nicht messen kannst. Jede ETL-Pipeline braucht:

  • Row-Counts auf jedem Stage (Bronze → Silver → Gold)
  • Lag-Metrics für Streaming-Jobs
  • Schema-Drift-Alerts
  • Data-Quality-Scores pro Pipeline-Run

Tools wie Harbinger Explorer machen Korrelation von Pipeline-Health mit Downstream-Quality einfach — surfacen Drift und Anomalien bevor sie deine Consumer erreichen.

# Prometheus-Metrics exposed von typischem Spark-Job
spark_streaming_records_in_total{job="cdc-bronze-landing"} 1402847
spark_streaming_records_out_total{job="cdc-bronze-landing"} 1402831
spark_streaming_processing_lag_seconds{job="cdc-bronze-landing"} 4.2
spark_streaming_batch_duration_seconds{job="cdc-bronze-landing"} 28.1

Das richtige Pattern wählen

SzenarioEmpfohlenes Pattern
OLTP-Source, low LatencyCDC + Streaming-Ingestion
File-basierte Sources (S3, SFTP)S3-Sensor + Batch
High-Volume-EventsKafka + Spark Structured Streaming
Regulatorisch / AuditMedallion + immutable Bronze
Legacy-Source, kein CDCFull-Load mit Partition-Replace
Mixed SLAsLambda-Architecture (Batch + Stream)

FAQ

Medallion oder direkt zu Gold? Bei kleinen Teams (< 5 Engineers) und einfachen Use Cases reicht oft Silver → Gold ohne Bronze-Layer. Aber Bronze hat einen Riesenvorteil: kompletter Audit-Trail. Du kannst Silver/Gold jederzeit aus Bronze rebuilden.

Airflow oder Dagster? Airflow: ausgereift, riesige Community, viele Operators. Dagster: modernerer Software-Engineering-Approach, bessere Local-Dev-Experience. Für DACH-Teams: Beides funktioniert, Airflow wenn ihr schon einen DevOps-Stack habt.

Wann reicht Polling statt CDC? Bei < 1M Changes/Tag und akzeptablen 5-15 min Latency. Wenn dein Use Case minutengenaue Daten erfordert oder Hard-Deletes wichtig sind: CDC.

Was kostet ein typischer ETL-Stack in EUR? Compute (Databricks/EMR): 1.500-5.000 EUR/Monat für mittlere Workloads. Storage (S3 in eu-central-1): 50-200 EUR/Monat pro TB. Orchestration (managed Airflow): 300-800 EUR/Monat.


Summary

Cloud-Native-ETL ist Engineering-Disziplin, kein Vendor-Checkbox. Die Patterns oben — Medallion-Layering, CDC-Ingestion, Schema-Evolution-Strategies, Idempotent-Loads und Event-driven-Orchestration — formen das Backbone jeder serious Data-Platform.

Start mit Medallion-Architecture als Foundation, adopt CDC für OLTP-Sources und enforce Idempotency von Tag 1. Add Observability auf jedem Layer und behandle Schema-Drift als First-Class-Concern.


Harbinger Explorer 7 Tage kostenlos testen und kriege End-to-End-Visibility in deine Cloud-Daten-Pipelines — von Ingestion-Lag bis Schema-Drift-Alerts, alles in einer Platform.

Stand: 14. Mai 2026.

H

Geschrieben von

Harbinger Team

Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastruktur­kritische Tech-Entscheidungen — keine Marketing- Folien, sondern echte Trade-offs aus Production-Workloads.

Hat dir das geholfen?

Jede Woche ein neuer Artikel über DACH-Cloud, Data und AI — direkt in dein Postfach. Kein Spam, kein Marketing-Sprech.

Kein Spam. 1-Klick-Abmeldung. Datenschutz bei Loops.so.