Wenn Datenbank-Migrationen schiefgehen: Warum Roll-Forward besser ist als Rollback
Sie haben gerade eine Datenbank-Migration deployed, die eine Spalte phone_number zur Tabelle users hinzugefügt hat. Die Migration lief erfolgreich. Dann stellt Ihr Team fest, dass der Anwendungscode, der diese Spalte nutzt, noch nicht deployed wurde. Jede neue Benutzerregistrierung schlägt jetzt fehl, weil der alte Code versucht, einen INSERT ohne Wert für die neue NOT-NULL-Spalte auszuführen.
Ihr Produktivsystem ist kaputt. Was tun?
Die meisten Teams greifen instinktiv zur Down-Migration – dem Skript, das die Änderung rückgängig macht und die Spalte entfernt. Doch dieser Instinkt kann mehr Schaden anrichten als das ursprüngliche Problem. Es gibt einen besseren Ansatz: Roll-Forward.
Das Problem mit Down-Migrationen
Down-Migrationen sehen auf dem Papier sauber aus. Sie schreiben eine up-Migration, die eine Spalte hinzufügt, und eine down-Migration, die sie entfernt. Wenn etwas schiefgeht, führen Sie die Down-Migration aus, und alles kehrt zum ursprünglichen Zustand zurück.
In der Praxis sind Down-Migrationen aus mehreren Gründen gefährlich.
Erstens ist Datenverlust nahezu garantiert. Wenn nach der Up-Migration Zeilen eingefügt oder aktualisiert wurden, verschwinden diese Werte beim Löschen der Spalte. Sie verlieren möglicherweise Kundendaten, die nicht wiederherstellbar sind.
Zweitens erzeugen Down-Migrationen eine Diskrepanz zwischen Ihrem Anwendungscode und Ihrem Datenbankschema. Wenn Ihr Anwendungscode bereits die Existenz der neuen Spalte erwartet, führt deren Entfernung zu Laufzeitfehlern. Sie müssten auch den alten Anwendungscode deployen, was die Koordination mehrerer gleichzeitiger Rollbacks erfordert.
Drittens werden Down-Migrationen selten getestet. Teams schreiben sie als nachträglichen Einfall, oft mit Fehlern, die erst in einem echten Notfall auftreten. Ein ungetestetes Skript während einer Störung gegen die Produktion laufen zu lassen, ist ein Rezept für noch mehr Ausfallzeit.
Was ist Roll-Forward?
Roll-Forward ist eine Strategie, bei der Sie eine Migration niemals rückgängig machen. Stattdessen schreiben Sie eine neue Migration, die das Problem behebt, wenn eine Migration Probleme verursacht. Die Datenbank bewegt sich vorwärts in einen korrigierten Zustand, nicht rückwärts in einen vorherigen Zustand.
Bezogen auf unser Beispiel: Anstatt eine Down-Migration auszuführen, um phone_number zu entfernen, schreiben Sie eine neue Migration, die die Spalte nullable macht oder einen Standardwert hinzufügt. Die Spalte bleibt erhalten, aber die Einschränkung, die die Fehler verursacht hat, wird entfernt. Neue Benutzerregistrierungen funktionieren wieder, und alle bereits in phone_number gespeicherten Daten bleiben erhalten.
So sieht die Fix-Migration in SQL aus:
-- version_002: phone_number-Einschränkung korrigieren
-- Diese Migration macht phone_number nullable, damit alter Anwendungscode
-- Zeilen einfügen kann, ohne einen Wert anzugeben.
ALTER TABLE users
ALTER COLUMN phone_number DROP NOT NULL;
Jede Migration wird zu einer kumulativen Änderung. Die erste Migration hat die Spalte hinzugefügt. Die zweite Migration hat die Einschränkung der Spalte korrigiert. Der Migrationstracker zeichnet beide Änderungen sequenziell auf, sodass Sie sehen können, dass version_002 version_001 korrigiert hat, ohne deren Historie zu löschen.
Warum Teams Roll-Forward bevorzugen
Der größte Vorteil ist der vollständige Ausschluss von Datenverlust. Wenn Ihre erste Migration 500 Telefonnummern gespeichert hat, bevor Sie das Problem entdeckten, überleben diese Nummern die Korrektur. Eine Down-Migration hätte sie dauerhaft gelöscht.
Roll-Forward hält auch Ihren Anwendungscode und Ihr Datenbankschema synchron. Da die Spalte weiterhin existiert, funktioniert jeder Anwendungscode, der phone_number liest, weiterhin. Sie müssen kein gleichzeitiges Code-Rollback koordinieren. Sie korrigieren die Datenbank und dann den Anwendungscode in Ihrem eigenen Tempo.
Dieser Ansatz spiegelt wider, wie Teams mit Fehlern im Anwendungscode umgehen. Wenn ein Fehler in die Produktion gelangt, machen Sie nicht die gesamte Codebasis auf die Version von letzter Woche rückgängig. Sie pushen einen Fix. Datenbank-Migrationen sollten genauso funktionieren: Der Fix ist eine neue Migration, keine Umkehrung.
Wenn Roll-Forward komplex wird
Nicht jeder Roll-Forward-Fix ist so einfach wie das Ändern einer Spalteneinschränkung. Stellen Sie sich eine Migration vor, die den Datentyp einer Spalte von VARCHAR in INTEGER geändert hat. Wenn die Konvertierung vorhandene Daten abgeschnitten oder beschädigt hat, könnte Ihre Fix-Migration Folgendes erfordern:
- Hinzufügen einer neuen Spalte mit dem ursprünglichen Datentyp
- Kopieren der Daten aus der beschädigten Spalte unter Anwendung von Transformationen zur Wiederherstellung der Werte
- Aktualisieren der Anwendungscode-Referenzen zur Nutzung der neuen Spalte
- Löschen der beschädigten Spalte in einer späteren Migration
Dies ist mehr Arbeit als eine einfache Down-Migration. Aber es ist auch sicherer. Sie können die Fix-Migration zuerst in einer Staging-Umgebung ausführen, die Datenwiederherstellungslogik überprüfen und erst dann in der Produktion anwenden. Eine Down-Migration bietet kein solches Sicherheitsnetz – sie löscht einfach die Spalte und hofft auf das Beste.
Die entscheidende Erkenntnis ist, dass Roll-Forward nicht erfordert, dass Sie jeden möglichen Fehler vor dem Deployment vorhersagen. Sie brauchen nur das Vertrauen, dass Ihr Team einen Fix schreiben kann, falls etwas schiefgeht. Dies verlagert das Risiko von der Prävention (die unmöglich perfekt ist) zur Wiederherstellung (eine Fähigkeit, die Sie üben können).
Praktische Checkliste für Roll-Forward
Bevor Sie sich als Team für Roll-Forward entscheiden, stellen Sie sicher, dass diese Praktiken etabliert sind:
Nutzen Sie diesen Entscheidungsbaum, wenn eine Migration Probleme verursacht:
- Jede Migration muss theoretisch umkehrbar sein, aber nicht unbedingt im Code. Verstehen Sie, was eine Down-Migration tun würde, aber schreiben Sie keine, es sei denn, Sie haben einen spezifischen Grund dafür.
- Testen Sie Ihre Fix-Migrationen zuerst im Staging. Führen Sie die ursprüngliche Migration aus, erzeugen Sie das Fehlerszenario und wenden Sie dann die Fix-Migration an. Überprüfen Sie anschließend die Datenintegrität.
- Halten Sie Ihren Migrationstracker zuverlässig. Ändern oder löschen Sie niemals manuell Migrationsdatensätze. Der Tracker ist Ihr Prüfpfad, um zu verstehen, was und wann sich geändert hat.
- Dokumentieren Sie die Fehlerart. Wenn Sie eine Fix-Migration schreiben, fügen Sie einen Kommentar hinzu, der erklärt, was schiefgelaufen ist und warum der Fix funktioniert. Dies hilft zukünftigen Teammitgliedern, die ähnliche Muster antreffen.
- Üben Sie Roll-Forward-Szenarien. Führen Sie vierteljährlich eine Übung durch, bei der jemand absichtlich eine fehlerhafte Migration einspielt, und das Team übt, unter Zeitdruck einen Fix zu schreiben und zu deployen.
Das Fazit
Down-Migrationen sind eine Falle. Sie versprechen Einfachheit, liefern aber Datenverlust, Koordinationsprobleme und ungetestete Notfallskripte. Roll-Forward behandelt Datenbankänderungen wie Codeänderungen: Wenn etwas kaputt geht, reparieren Sie es vorwärts, nicht rückwärts.
Wenn das nächste Mal eine Migration schiefgeht, widerstehen Sie dem Drang, sie rückgängig zu machen. Schreiben Sie stattdessen eine Fix-Migration. Ihre Daten, Ihre Anwendung und der Verstand Ihres Teams werden es Ihnen danken.