Inhaltsverzeichnis21 Abschnitte
- TL;DR
- Was "Cloud-Native ETL" tatsächlich bedeutet
- Pattern 1: Die Medallion-Architecture
- Terraform: S3-Bucket-Struktur für Medallion
- Pattern 2: Change Data Capture (CDC) Ingestion
- Debezium + Kafka: Core-Config
- CDC-Events Downstream handhaben
- Pattern 3: Schema-Evolution ohne Pipelines zu brechen
- Strategy 1: Schema-Registry (Apache Avro)
- Strategy 2: Delta-Lake-Schema-Evolution
- Pattern 4: Idempotent Loads
- UPSERT-Pattern mit MERGE
- Partition-Replace-Pattern
- Pattern 5: Event-Driven Orchestration
- Airflow mit S3-Sensor
- Terraform: EventBridge-Rule für S3-Triggered-Lambda
- Pattern 6: Dead-Letter-Queues für Failed Records
- Observability für ETL-Pipelines
- Das richtige Pattern wählen
- FAQ
- Summary
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.
| Layer | Zweck | Format | Update-Frequency |
|---|---|---|---|
| Bronze | Raw-Ingestion, keine Transformation | Parquet / Delta | Near-Real-Time |
| Silver | Cleaned, dedupliziert, typed | Delta | 15-60 min |
| Gold | Business-ready Aggregates | Delta / Iceberg | Stü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-Type | Schema-Registry | Delta-Auto-Merge | Manuelle Migration |
|---|---|---|---|
| Add Nullable Column | BACKWARD-Compat | Auto | Ja |
| Remove Column | Nur FULL-Compat | Failed | Manuell |
| Type-Change | Breaking | Failed | Manuell |
| Add Required Column | Breaking | Failed | Manuell |
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
| Szenario | Empfohlenes Pattern |
|---|---|
| OLTP-Source, low Latency | CDC + Streaming-Ingestion |
| File-basierte Sources (S3, SFTP) | S3-Sensor + Batch |
| High-Volume-Events | Kafka + Spark Structured Streaming |
| Regulatorisch / Audit | Medallion + immutable Bronze |
| Legacy-Source, kein CDC | Full-Load mit Partition-Replace |
| Mixed SLAs | Lambda-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.
Geschrieben von
Harbinger Team
Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastrukturkritische 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.