Change Data Capture liest das eigene Transaktions-Log der Datenbank und verwandelt jedes Insert, Update und Delete in ein geordnetes Event. Statt das Ledger nach Zeilen abzufragen, die sich vielleicht geändert haben, abonnierst du die Änderungen in dem Moment, in dem die Quelle sie committet. Für Finanz-KI bedeutet das: Features und Retrieval-Indizes bleiben auf wenige Sekunden am System of Record dran, und das Quellsystem merkt kaum, dass du da bist.
Die übliche Alternative ist eine geplante Abfrage, die alles zieht, was seit dem letzten Lauf verändert wurde. Das funktioniert, bis es das nicht mehr tut. Ein Repoll ist nur so aktuell wie sein Intervall, es übersieht jede Zeile, die zwischen zwei Läufen geändert und wieder zurückgesetzt wurde, und ein Delete sieht es überhaupt nicht, außer du vergleichst vollständige Snapshots. Schlimmer noch: Die Abfrage, die die jüngsten Änderungen findet, ist oft ein Full Scan über eine Tabelle ohne den passenden Index. So kostet die gewünschte Aktualität das transaktionale System genau die Last, die es sich zum Quartalsende am wenigsten leisten kann.
Warum das Log das Polling schlägt
Ein Transaktions-Log enthält bereits genau das, was du mit Polling zu rekonstruieren versuchst: die exakte Abfolge der committeten Änderungen, jeweils mit Zeitstempel und Position. Es direkt zu lesen bringt dir drei Dinge, die ein Poll nicht liefern kann.
- Das Log ist vollständig. Löschungen und zwischenzeitliche Updates treffen jeweils als eigenes Event ein. Ein Poll, der auf
updated_ataufsetzt, sieht nie eine Zeile, die zwischen zwei Läufen eingefügt und wieder gelöscht wurde. Im Finanzbereich könnte diese Zeile eine korrigierte Zahlung oder eine stornierte Buchung sein, die du im Audit Trail brauchst. - Das Log ist geordnet. Log-Positionen geben dir eine totale Ordnung pro Tabelle und eine Möglichkeit, über Kausalität zu argumentieren. Wenn ein Zahlungsstatus in acht Sekunden von pending → settled → returned wandert, bekommst du alle drei Übergänge in ihrer Reihenfolge, nicht bloß den, der beim Poll gerade aktuell war.
- Das Log kostet die Quelle fast nichts. Die Datenbank schreibt es ohnehin für Durability und Replikation, und ein CDC-Connector liest es tailend mit, so wie es eine Read Replica tut. Du lädst der Primärdatenbank in den geschäftigsten Stunden des Monats keine zusätzliche Abfragelast auf.
Standardmäßig greifen wir zu log-basiertem CDC: Postgres Logical Decoding, MySQL Binlog, SQL Server Change Tracking oder die Change Streams, die Debezium darüber normalisiert. Query-basiertes CDC über eine updated_at-Spalte ist ein Fallback für Quellen, für die wir keinen Replication Slot bekommen, und wir kennzeichnen es als verlustbehaftet bei Löschungen, damit niemand weiter unten annimmt, es sei vollständig.
Point-in-Time-Korrektheit aus einem Stream gewinnen
Der Grund, warum CDC für Modelle zählt und nicht nur für Dashboards, ist, dass das Change Log ein sauberes Substrat für Point-in-Time-korrekte Features ist. Jedes Event trägt den Commit-Zeitstempel der Quelle. Wenn du Features zu diesem Zeitstempel berechnest statt zu dem Moment, in dem deine Pipeline das Event zufällig verarbeitet hat, erhältst du eine Feature-Historie, die dem entspricht, was zu jedem Zeitpunkt tatsächlich wissbar war.
Genau in diesem Unterschied versteckt sich Leakage. Angenommen, die Risikostufe eines Kunden wurde am 14. hochgestuft, und ein Modell entscheidet über eine Transaktion mit Datum 10. Wenn dein Feature Store die aktuelle Stufe abbildet, hast du stillschweigend vier Tage Zukunftsinformation ins Training durchsickern lassen, und deine Offline-Auswertung wird besser aussehen, als es die Produktion je sein wird. CDC lässt dich das sauber vermeiden, denn das Log sagt dir, dass die Stufe zum Stand des 10. die alte war. Du liest das Log bis zum Entscheidungszeitpunkt des Labels und hörst dort auf.
Ein paar Dinge, auf denen wir bestehen, um das ehrlich zu halten:
- Trenne Event Time und Ingestion Time überall. Event Time ist der Commit der Quelle; Ingestion Time ist der Zeitpunkt, zu dem der Connector es gesehen hat. Features setzen auf Event Time auf. Das Latenz-Monitoring setzt auf die Lücke zwischen beiden auf.
- Behandle verspätete und außer der Reihe eintreffende Events als Normalfall, denn in einer verteilten Quelle sind sie das. Gefensterte Aggregate brauchen eine Grace Period und eine definierte Policy dafür, was passiert, wenn eine Änderung nach Schließen des Fensters landet.
- Bewahre die Lineage. Wenn sich ein Feature-Wert ändert, solltest du ihn zurück auf das konkrete Change Event und die Quelltransaktion verfolgen können, die ihn erzeugt haben. Diese Nachverfolgung ist es, die eine Modellentscheidung Monate später für einen Prüfer oder Auditor nachvollziehbar macht.
Wo CDC leise bricht, und wie wir es eindämmen
CDC ist nicht umsonst, und die Failure Modes sind spezifisch. Der wichtigste ist Schema Drift. Ein Quellteam fügt eine Spalte hinzu, benennt eine andere um oder ändert einen Typ, und ein naiver Connector lässt entweder das Feld fallen oder bringt den Stream zum Stillstand. Wir setzen einen Data Contract vor den Connector, sodass eine Schemaänderung ein ausgehandeltes Ereignis mit einer Version ist und kein Pager-Alarm um drei Uhr nachts. Kompatible Änderungen fließen durch; brechende Änderungen scheitern laut an der Grenze, statt Features still zu korrumpieren.
Der zweite ist Exactly-Once-Delivery, was Ende zu Ende wirklich schwer ist. Die meisten CDC-Pipelines sind At-Least-Once, das heißt, dieselbe Änderung kann nach einem Connector-Neustart zweimal eintreffen. Für den Finanzbereich ist das nur dann in Ordnung, wenn dein Downstream idempotent ist. Wir schlüsseln Writes auf den Primary Key der Quelle plus Log-Position, sodass ein wiederabgespieltes Event überschreibt statt doppelt zu zählen. Ein dupliziertes Settlement-Event sollte den Saldo unverändert lassen, nicht zweimal bewegen.
Der dritte ist die Abgleichslücke. Streams verlieren Events, Connectors laufen hinterher, Replication Slots werden unter Plattendruck verworfen. Wir lassen CDC nie den einzigen Pfad sein. Ein täglicher Batch berechnet dieselben Aggregate aus einem vollständigen Snapshot neu und vergleicht sie mit dem, was der Stream produziert hat. Wenn sie über eine Toleranz hinaus abweichen, gewinnt die Batch-Zahl und die Differenz wird geloggt. Dieser Job ist langweilig, und er ist genau das, was dir erlaubt, dem schnellen Pfad die restliche Zeit zu vertrauen.
Delete Handling verdient eine eigene Erwähnung. In vielen Finanzsystemen wird ein Datensatz nie physisch entfernt, sondern durch einen korrigierenden Eintrag ersetzt, und ein Hard Delete signalisiert meist etwas, das du wissen willst. Erfasse Löschungen als erstklassige Events, bewahre den Tombstone und lass den Downstream entscheiden, ob er entfernt oder als ersetzt markiert. Das Delete wegzuwerfen, weil dein Sink nur Upserts versteht, ist genau der Weg, auf dem eine stornierte Transaktion in einem Feature weiterlebt, das sie hätte vergessen sollen.
Mit diesen Leitplanken versehen, verwandelt CDC den Data Layer von etwas, das du nach Zeitplan abfragst, in etwas, das dir sagt, wann es sich geändert hat. Die darauf aufsetzenden Modelle sehen dieselbe Welt wie das Ledger, nur ein paar Sekunden versetzt, und sie sehen die Historie dieser Welt in genau der Reihenfolge, in der sie tatsächlich geschehen ist.
Häufige Fragen
Ersetzt CDC nächtliche Batch-Ladevorgänge vollständig?
Selten, und wir drängen auch nicht darauf. CDC hält die operativen Tabellen und Retrieval-Indizes über den Tag hinweg aktuell, während ein nächtlicher Abgleichs-Batch die maßgebliche Wahrheit bleibt, der alles auffängt, was der Stream verloren oder umsortiert hat.
Kann ich CDC betreiben, ohne die Konfiguration der Quelldatenbank anzufassen?
Log-basiertes CDC benötigt das aktivierte Write-Ahead- bzw. Binary-Log und einen Replication Slot oder ein Äquivalent, was eine DBA-Änderung bedeutet. Query-basiertes CDC über eine updated_at-Spalte braucht keine Server-Konfiguration, übersieht aber Löschungen und Hard Updates. Deshalb setzen wir es nur dort ein, wo das Schema einen monoton steigenden Zeitstempel garantiert.
Wie verhindert ihr, dass eine CDC-Feature-Pipeline Zukunftsinformationen ins Training durchsickern lässt?
Jedes Change Event trägt den Commit-Zeitstempel der Quelle, und Features werden zu genau diesem Zeitpunkt berechnet, niemals zum Zeitpunkt der Ingestion. Das Training liest das Log bis zum Entscheidungszeitpunkt des Labels, sodass ein danach geschriebener Wert für das Modell unsichtbar bleibt.