Cloud allgemein

Change Data Capture erklärt: Log-based CDC mit Debezium in Production

Praktischer Guide zu CDC-Patterns — log-based, trigger-based und polling — mit Debezium-Konfig und Kafka-Connect-Integration.

Harbinger Team3. April 20267 Min. LesezeitAktualisiert 14.5.2026
  • cdc
  • debezium
  • kafka
  • data-engineering
  • streaming
  • postgres
  • real-time
Inhaltsverzeichnis16 Abschnitte

Change Data Capture erklärt: Log-based CDC mit Debezium in Production

TL;DR

PatternLatencySource-ImpactKomplexität
Log-based (WAL / binlog)SekundenSehr niedrigHoch (Setup)
Trigger-basedSekundenMittelMittel
Query-based (Polling)MinutenHochNiedrig

Log-based CDC ist der Gold-Standard für Production-Workloads. Die anderen sind Stepping-Stones oder Fallbacks.

Deine Operational-Database interessiert sich nicht für dein Warehouse. Jedes Mal wenn ein Customer sein Profile updatet, eine Order canceled oder die E-Mail ändert, lebt dieser State-Change in PostgreSQL oder MySQL — und dein Analytics-Layer ist sofort out-of-date. Change Data Capture (CDC) löst das, indem es Row-Level-Changes von einer Source-DB in Near-Real-Time an Downstream-Systems streamed.

Dieser Guide geht durch die drei CDC-Hauptpatterns, wie Debezium log-based CDC production-ready macht und wie du das in Kafka Connect wirst.

Die drei CDC-Patterns

1. Log-Based CDC

Jede major DB pflegt ein Transaction-Log für Crash-Recovery. PostgreSQL nennt es Write-Ahead-Log (WAL). MySQL nennt es Binary-Log (binlog). Diese Logs enthalten einen kompletten, geordneten Record jedes Row-Level-Changes — inklusive Deletes.

Log-based CDC tappt diesen Stream als sekundärer Consumer, ohne die Source-App zu modifizieren. Es liest das Transaction-Log, extrahiert Change-Events und forwardet downstream.

Advantages:

  • Keine zusätzliche Load auf Source-Queries
  • Captures Deletes und Updates, nicht nur Inserts
  • Sub-Second-Latency erreichbar
  • Keine App-Level-Changes nötig

Limitations:

  • Braucht DB-Level-Privileges (Replication-Role)
  • Log-Retention muss konfiguriert werden — Logs werden getrunkated
  • Schema-Changes brauchen careful Handling downstream

PostgreSQL — Logical-Replication enablen:

-- postgresql.conf: set wal_level = logical (requires DB restart)

-- Create a replication slot für Debezium
SELECT pg_create_logical_replication_slot('debezium_slot', 'pgoutput');

-- Grant replication-Privileg an CDC-User
ALTER ROLE cdc_user REPLICATION LOGIN;

2. Trigger-Based CDC

DB-Triggers feuern auf INSERT, UPDATE oder DELETE und schreiben eine Kopie der changed Row in eine dedicated Changelog-Tabelle. Ein Downstream-Job pollt die Tabelle und verarbeitet neue Rows.

-- PostgreSQL: trigger-based CDC example
CREATE TABLE customers_changes (
    change_id    BIGSERIAL PRIMARY KEY,
    change_type  VARCHAR(10),
    changed_at   TIMESTAMPTZ DEFAULT NOW(),
    old_data     JSONB,
    new_data     JSONB
);

CREATE OR REPLACE FUNCTION capture_customer_changes()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'DELETE' THEN
        INSERT INTO customers_changes (change_type, old_data)
        VALUES ('DELETE', row_to_json(OLD)::jsonb);
    ELSIF TG_OP = 'UPDATE' THEN
        INSERT INTO customers_changes (change_type, old_data, new_data)
        VALUES ('UPDATE', row_to_json(OLD)::jsonb, row_to_json(NEW)::jsonb);
    ELSE
        INSERT INTO customers_changes (change_type, new_data)
        VALUES ('INSERT', row_to_json(NEW)::jsonb);
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_customers_cdc
AFTER INSERT OR UPDATE OR DELETE ON customers
FOR EACH ROW EXECUTE FUNCTION capture_customer_changes();

Trigger-based CDC funktioniert, aber jeder Write zur Source-Table kostet Trigger-Overhead. Die Changelog-Tabelle braucht auch regular Pruning, und der Ansatz skaliert nicht graceful unter High-Write-Loads.

3. Query-Based CDC (Polling)

Der einfachste Approach: alle N Minuten eine Query laufen lassen, die Rows seit letztem Checkpoint mit updated_at-Timestamp-Column selectet.

-- Query-based CDC: fetch rows changed since last run
-- Standard SQL — works on PostgreSQL, MySQL, and most other RDBMS
SELECT *
FROM customers
WHERE updated_at > '2024-01-15 10:00:00'
ORDER BY updated_at ASC;

Das fundamentale Problem: Hard-Deletes sind unsichtbar. Wenn eine Row gelöscht wird, gibt es kein updated_at zum Tracken. Soft-Deletes (eine deleted_at-Column) lösen das partiell, brauchen aber Disziplin über die ganze App.

Query-based CDC ist okay für kleine Tables, infrequent Updates oder Environments, wo du die Source-Schema kontrollierst. Für High-Volume-Production ein Kompromiss.

Debezium: Log-Based CDC, das tatsächlich shippt

Debezium ist eine OSS-CDC-Plattform auf Apache Kafka. Liest Transaction-Logs von PostgreSQL, MySQL, MongoDB, SQL Server, Oracle und mehr — und emittiert strukturierte Change-Events an Kafka-Topics.

Jedes Event enthält den vollen Before/After-State der Row, Operation-Type (c, u, d, r) und Metadata: Source-Table, Transaction-ID, LSN, Wall-Clock-Timestamp. Reicher und reliable als alles, was Polling-based produzieren kann.

Debezium PostgreSQL-Connector-Konfiguration

{
  "name": "customers-postgres-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "postgres-host",
    "database.port": "5432",
    "database.user": "cdc_user",
    "database.password": "your_password",
    "database.dbname": "production_db",
    "database.server.name": "prod",
    "table.include.list": "public.customers,public.orders",
    "plugin.name": "pgoutput",
    "slot.name": "debezium_slot",
    "publication.name": "debezium_publication",
    "topic.prefix": "prod",
    "snapshot.mode": "initial"
  }
}

Produziert Kafka-Topics prod.public.customers und prod.public.orders. Jeder Insert, Update, Delete auf diesen Tables wird zur Kafka-Message.

Die Debezium-Event-Struktur

{
  "op": "u",
  "before": {
    "id": 42,
    "email": "old@example.com",
    "updated_at": 1705312800000
  },
  "after": {
    "id": 42,
    "email": "new@example.com",
    "updated_at": 1705316400000
  },
  "source": {
    "version": "2.5.0.Final",
    "connector": "postgresql",
    "name": "prod",
    "ts_ms": 1705316400123,
    "db": "production_db",
    "schema": "public",
    "table": "customers",
    "txId": 1234567,
    "lsn": 987654321
  }
}

op-Werte: c = create (Insert), u = update, d = delete, r = read (aus initialem Snapshot).

Deployen mit Kafka Connect

Debezium läuft als Kafka-Connect-Source-Connector. Wenn du Kafka Connect schon operiert, ist Debezium-Deployment straightforward: Connector-JAR zum Connect-Plugin-Path adden und Config an Connect-REST-API POSTen.

# Connector via Kafka Connect REST-API registrieren
curl -X POST http://kafka-connect:8083/connectors \
  -H "Content-Type: application/json" \
  -d @customers-postgres-connector.json

# Connector-Status checken
curl http://kafka-connect:8083/connectors/customers-postgres-connector/status

Vom Kafka-Topic kannst du Change-Events zu jedem Sink routen: Object-Storage (S3, GCS), Warehouse (Snowflake, BigQuery) oder Elasticsearch. Confluent Hub liefert ready-made Sink-Connectors für die meisten Targets.

Schema-Changes handhaben

Die trickigste Long-Term-Challenge ist Schema-Evolution. Wenn das Source-Team eine Column addet, müssen CDC-Consumer alte und neue Event-Formate handhaben ohne zu failen.

Debezium integriert mit Confluent Schema Registry (oder kompatiblen Alternativen wie Karapace), um Avro-, Protobuf- oder JSON-Schema-Evolution zu managen. Mit BACKWARD- oder FULL-Compatibility-Mode ist Adden von Nullable Columns safe. Dropping oder Renaming Columns ist immer breaking.

Best Practice: Source-Schema-Changes als Deployment-Event behandeln. Schema-Registry-Compatibility-Checks in CI-Pipeline nutzen und Changes mit Downstream-Consumer koordinieren, bevor Rollout. Debezium mit einem Data-Contract-Prozess paaren schließt den Loop properly.

CDC vs. Full-Loads: Wann was?

SzenarioCDCFull-Load
High-Volume-OLTP (>1M Changes/Tag)JaNein, zu langsam
Kleine Reference-Tables (<10k Rows)OverkillJa, einfach
Hard-Deletes capturenJaNein, unsichtbar
Source-DB ohne Replication-SupportNeinJa
Near-Real-Time-Latency (<1 min)JaNein
Team ohne Kafka-InfraNein, komplexJa

Common Pitfalls

WAL-Retention zu kurz. Wenn Debezium-Connector länger offline ist als das Log-Retention-Window, verliert er seine Position und muss re-snapshotten. wal_keep_size (PostgreSQL) generös setzen und Replication-Slot-Lag continuously monitoren.

Initial-Snapshot nicht planen. Bevor Streaming neuer Changes nimmt Debezium einen konsistenten Snapshot existierender Daten. Bei großen Tables kann das Stunden laufen. Planen — und Snapshot validieren, bevor Real-Time-Streaming enablen.

Tombstone-Events ignorieren. Nach Emit eines Delete-Events publisht Debezium eine Null-Value-Tombstone-Message zum selben Key. Manche Consumer failen silently. Explizit handhaben.

Null-Before-State bei Inserts. Für op: c ist before immer null. Immer op checken, bevor before zugreifen.

Compacted Topics removen Deletes. Bei log-compacted Kafka-Topics verschwinden Tombstone-Messages schließlich. Für CDC-Streams, die volle History replayen müssen, Retention-based (nicht Compaction-based) Topics nutzen.

CDC-Daten explorieren, wenn sie landen

Wenn dein CDC-Stream als Parquet oder CSV in Object-Storage landet, musst du noch Current-State rekonstruieren — Inserts, Updates und Deletes in Sequence applyen. Tools wie dbt handhaben das mit Snapshot-Models. Für Ad-Hoc-Validation — "hat dieser Record heute geändert? Wie sah er vorher aus?" — willst du den Raw-Change-Log schnell queryen ohne Infra-Spin-Up.

Harbinger Explorer lässt dich Parquet oder CSV uploaden und direkt im Browser mit DuckDB WASM queryen. In Deutsch fragen: "Zeige alle Rows, wo op gleich u und customer_id gleich 42" — die AI generiert SQL gegen dein tatsächliches Schema. Schneller Weg, CDC-Correctness während Dev zu validieren.

FAQ

Was passiert, wenn der Source-Server crasht während CDC läuft? Debezium pflegt seine Position via Replication-Slot. Nach Recovery liest er ab letzter Position weiter — keine Datenverlust solang WAL-Retention reicht.

Wie monitor ich Replication-Lag? PostgreSQL: SELECT * FROM pg_replication_slots; zeigt confirmed_flush_lsn vs. pg_current_wal_lsn(). Bei großem Delta hat dein Consumer Lag. Prometheus-Exporter dafür ist verfügbar.

Können mehrere CDC-Consumer dieselbe Source nutzen? Ja, aber jeder braucht eigenen Replication-Slot. Slots akkumulieren WAL, also alle aktiv halten oder Slots droppen, sonst läuft die Disk voll.

Was bei Schema-Changes auf der Source-DB? Debezium captures DDL-Events in Schema-History-Topic. Bei BACKWARD-Compatibility addst du Nullable-Columns safe. Type-Changes brauchen Coordination — Source und Consumer simultan deployen.

Fazit

CDC — speziell log-based CDC via Debezium — ist der zuverlässigste Weg, Downstream-Systems mit Operational-Datenbanken in Real-Time zu synchronisieren. Nicht trivial zu setupen, aber für High-Volume-Latency-sensitive Pipelines das richtige Tool. Mit einer Table starten, Event-Format End-to-End validieren, für Schema-Changes planen und ausweiten.

Zum Strukturieren der CDC-Daten, die in deinem Lakehouse landen, lies den Medallion-Architecture-Guide — er zeigt, wie Raw-Change-Events in eine Bronze → Silver → Gold-Pipeline passen.

Weiterlesen

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.