Sofortantwort
Schema Evolution einfach erklärt
Änderung von Datenschemata ohne Breaking Changes.
- Kurz gesagt
- Backward Compatible: Neue Reader lesen alte Daten
- Typischer Einsatz
- Data Lake, Kafka, APIs
- Wichtig zu wissen
- Wichtig für Data Lakes, Event Streaming, APIs
Schema Evolution im Überblick
Schema Evolution erlaubt Änderungen an Datenstrukturen, ohne alles kaputt zu machen.
Kompatibilitätstypen:
| Typ | Bedeutung |
|---|---|
| Backward | Neuer Code liest alte Daten |
| Forward | Alter Code liest neue Daten |
| Full | Beides |
Technisch betrachtet
Sichere Änderungen
✅ Sicher:
- Feld hinzufügen (mit Default)
- Optionales Feld hinzufügen
- Alias für Feld
❌ Unsicher:
- Pflichtfeld entfernen
- Typ ändern (int → string)
- Feld umbenennen
Avro Schema Evolution
// Version 1
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"}
]
}
// Version 2 (backward compatible)
{
"type": "record",
"name": "User",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"},
{"name": "email", "type": ["null", "string"], "default": null}
]
}
Kompatibilität richtig herum denken
Die Begriffe Backward und Forward werden leicht verwechselt. Eine Merkhilfe: Die Richtung bezieht sich immer auf den Reader.
| Szenario | Benötigte Kompatibilität |
|---|---|
| Consumer wird zuerst aktualisiert, Producer später | Backward: neuer Reader muss alte Events verstehen |
| Producer wird zuerst aktualisiert, Consumer später | Forward: alter Reader muss neue Events tolerieren |
| Deployment-Reihenfolge unklar oder gemischt | Full: beide Richtungen absichern |
In Event-Streaming-Systemen mit vielen unabhängigen Teams ist Full Compatibility die sicherste Wahl – sie schränkt die erlaubten Änderungen zwar am stärksten ein (praktisch nur optionale Felder mit Default), verhindert aber Deployment-Abhängigkeiten zwischen Teams.
Umbenennen und Typänderungen: der Zwei-Schritte-Trick
Breaking Changes lassen sich oft in mehrere kompatible Schritte zerlegen. Statt ein Feld direkt umzubenennen:
Schritt 1: Neues Feld mit neuem Namen hinzufügen (mit Default),
Producer schreibt beide Felder parallel
Schritt 2: Alle Consumer auf das neue Feld migrieren
Schritt 3: Altes Feld als deprecated markieren,
später in einer Major-Version entfernen
Dasselbe Muster funktioniert für Typänderungen: neues Feld mit neuem Typ einführen, doppelt schreiben, Consumer migrieren, altes Feld abkündigen. Das dauert länger als ein harter Schnitt, vermeidet aber koordinierte Big-Bang-Deployments.
Schema Registry in der Praxis
Eine Schema Registry prüft neue Schema-Versionen automatisch gegen die konfigurierte Kompatibilitätsregel, bevor sie akzeptiert werden. Producer und Consumer referenzieren Schemas über eine ID statt sie mitzuschicken – das spart Speicherplatz pro Nachricht und macht die Registry zur zentralen Wahrheitsquelle. Wichtig ist, die Kompatibilitätsprüfung zusätzlich in die CI-Pipeline einzubauen: Ein inkompatibles Schema soll den Build brechen, nicht erst das Deployment.
Typische Fehler in der Praxis
| Fehler | Folge |
|---|---|
| Pflichtfeld ohne Default hinzufügen | Alte Daten lassen sich mit neuem Schema nicht mehr lesen |
| Feld löschen und Namen später wiederverwenden | Alte Daten werden mit falscher Semantik interpretiert |
| Enum-Werte entfernen | Alte Events mit dem entfernten Wert brechen Consumer |
Kompatibilitätsmodus auf NONE stellen, „um schnell zu liefern” | Breaking Changes rutschen unbemerkt durch |
| Schemas nur in der Registry, nicht im Code-Repository | Kein Review-Prozess, keine Historie für Änderungen |
Als Grundregel gilt: Jede Schema-Änderung wie eine API-Änderung behandeln – mit Review, Versionierung und der Frage, wer die Daten in fünf Jahren noch lesen können muss. Gerade in Data Lakes liegen Parquet- oder Avro-Dateien oft Jahre unverändert; das Schema von heute muss auch für die Daten von damals funktionieren.