Warum ein Datenbank-Rollback nicht mit einem Anwendungs-Rollback vergleichbar ist
Wenn eine neue Version Ihrer Anwendung Fehler verursacht, ist die Lösung meist einfach: Sie drücken den Rollback-Button in Ihrer Deployment-Pipeline, und die alte Version kommt zurück. Der Server stoppt die fehlerhafte Code-Ausführung und startet die vorherige Version. Solange Sie keine Systemabhängigkeiten oder Konfigurationen geändert haben, läuft die Anwendung innerhalb weniger Minuten wieder normal.
Das funktioniert, weil Anwendungen von Natur aus zustandslos sind. Sie können gestoppt, neu gestartet oder zwischen Versionen gewechselt werden, ohne dauerhaft etwas zu verlieren. Die verarbeiteten Daten stammen von Benutzern oder aus der Datenbank. Fällt die App für ein paar Sekunden aus, bemerken Benutzer das vielleicht, aber es gehen keine Daten verloren. Sobald die alte Version wieder läuft, läuft alles weiter, als wäre nichts passiert.
Datenbanken funktionieren nicht so.
Die zustandsbehaftete Realität von Datenbanken
Eine Datenbank ist eine zustandsbehaftete Komponente. Sie speichert Daten, die über Anwendungsversionen hinweg erhalten bleiben müssen. Benutzerprofile, Transaktionen, Bestellaufzeichnungen, Konfigurationseinstellungen – all das lebt in der Datenbank und muss intakt bleiben. Wenn Sie das Datenbankschema ändern – eine Spalte hinzufügen, einen Datentyp ändern oder eine Tabelle löschen – zeichnet die Datenbank diese Änderung dauerhaft auf. Die bereits gespeicherten Daten kehren nicht automatisch in ihre vorherige Form zurück, nur weil Sie die Anwendung auf eine ältere Version zurückgesetzt haben.
Dies ist der grundlegende Unterschied, der viele Teams überrascht. Sie gehen davon aus, dass ein Datenbank-Rollback genauso funktioniert wie ein Anwendungs-Rollback: einen Rückwärtsbefehl ausführen, und alles ist wieder wie vor der Migration. In Wirklichkeit ist das Rückgängigmachen von Schemaänderungen weitaus komplexer und riskanter.
Ein konkretes Beispiel für das Problem
Stellen Sie sich vor, Ihr Team fügt der Tabelle users über eine Datenbankmigration eine Spalte phone_number hinzu. Die Migration läuft erfolgreich, und in den nächsten Stunden beginnen Benutzer, ihre Telefonnummern einzutragen. Dann entdeckt jemand einen Fehler im Anwendungscode, der diese Spalte ausliest. Das Team beschließt, die Anwendung auf die vorherige Version zurückzusetzen. Die App wird wiederhergestellt, und der Fehler verschwindet.
Aber die Spalte phone_number ist immer noch in der Datenbank. Die von Benutzern eingegebenen Daten sind noch vorhanden. Wenn Sie jetzt eine Rollback-Migration ausführen, um diese Spalte zu entfernen, sind alle diese Telefonnummern weg. Für immer. Und diese Daten werden möglicherweise bereits von anderen Funktionen genutzt oder von anderen Benutzern eingesehen. Sie können sie nicht einfach ohne Konsequenzen löschen.
Dieses Risiko des Datenverlusts ist der Grund, warum ein Datenbank-Rollback nicht auf die leichte Schulter genommen werden sollte. Jedes Mal, wenn eine Migration das Schema ändert, können Daten transformiert, verschoben oder gelöscht werden. Die Wiederherstellung des alten Schemas bedeutet die Wiederherstellung der alten Datenstruktur. Ohne einen Mechanismus, der garantiert, dass die Daten in ihren exakten vorherigen Zustand zurückversetzt werden können, kann ein Schema-Rollback zu inkonsistenten oder fehlenden Daten führen.
Das Problem der Code-Schema-Inkompatibilität
Neben dem Datenverlust gibt es ein zweites Problem: die Inkompatibilität zwischen Anwendungscode und Datenbankschema.
Wenn Sie die Anwendung auf eine ältere Version zurücksetzen, erkennt dieser alte Code möglicherweise die neuen Spalten oder Tabellen in der Datenbank nicht. Er könnte abstürzen, wenn er versucht, eine Spalte zu lesen, die er nicht erwartet, oder das Einfügen von Daten aufgrund einer ihm unbekannten Einschränkung fehlschlagen.
Wenn Sie umgekehrt eine Rollback-Migration ausführen, die eine Spalte entfernt, die noch vom aktuellen Anwendungscode verwendet wird, wird die App sofort abstürzen. Da Anwendungsbereitstellungen und Datenbankmigrationen selten genau zum gleichen Zeitpunkt ausgeführt werden, können Sie nicht garantieren, dass beide Seiten während eines Rollbacks synchron sind.
Diese Diskrepanz ist besonders in der Produktion gefährlich. Selbst ein paar Sekunden Inkonsistenz können Fehler, fehlgeschlagene Transaktionen oder beschädigte Daten verursachen, die nur schwer wiederherzustellen sind.
Warum die gleiche Rollback-Strategie nicht anwendbar ist
Ein Anwendungs-Rollback funktioniert, weil die alte Version einen bekannten, guten Zustand darstellt. Der Code ist derselbe wie vor dem Deployment. Die Umgebung ist dieselbe. Es ändert sich nur, welche Binärdatei ausgeführt wird.
Ein Datenbank-Rollback hat keinen solchen "bekannten guten Zustand". Das Schema und die Daten haben sich weiterentwickelt. Das Ausführen einer Rückwärtsmigration führt nicht zu genau derselben Datenbank wie zuvor. Es führt zu einem Schema, das wie das alte aussieht, aber mit Daten, die möglicherweise auf eine Weise transformiert, hinzugefügt oder entfernt wurden, die ohne sorgfältige Planung nicht umkehrbar ist.
Einige Teams versuchen, dies zu umgehen, indem sie vor jeder Migration ein vollständiges Datenbank-Backup erstellen. Dieser Ansatz hat seine eigenen Probleme:
- Die Wiederherstellung eines Backups dauert Zeit – oft Minuten oder Stunden, nicht Sekunden.
- Alle nach dem Backup geschriebenen Daten gehen verloren.
- Andere Dienste, die von derselben Datenbank abhängen, können während der Wiederherstellung ausfallen.
- Die Wiederherstellung selbst kann fehlschlagen und Sie in einen noch schlechteren Zustand versetzen.
Der sicherere Weg: Roll Forward
Aufgrund dieser Risiken betrachten viele erfahrene Teams den Datenbank-Rollback als letztes Mittel. Anstatt zu versuchen, eine fehlgeschlagene Migration rückgängig zu machen, bevorzugen sie ein Roll-Forward: Schreiben Sie eine neue Migration, die das Problem behebt, ohne das Schema umzukehren.
Wenn eine Migration beispielsweise versehentlich eine noch benötigte Spalte löscht, besteht der Roll-Forward-Ansatz darin, die Spalte in einer neuen Migration wieder hinzuzufügen, anstatt zu versuchen, das Löschen rückgängig zu machen. Dadurch bewegt sich das Schema in eine Richtung und vermeidet die Komplexität der Umkehrung von Datentransformationen.
Roll-Forward ist nicht immer möglich. Manchmal ist der Schaden zu groß, oder die Behebung erfordert eine Schemaänderung, die nicht als Vorwärtsmigration ausgedrückt werden kann. Aber in den meisten Fällen ist es sicherer als der Versuch eines Rollbacks, der zu Datenverlust oder Anwendungsfehlern führen könnte.
Praktische Checkliste für die Sicherheit von Datenbankänderungen
Bevor Sie eine Datenbankmigration in der Produktion ausführen, gehen Sie diese Checkliste durch:
- Kann die Migration ohne Datenverlust rückgängig gemacht werden? Wenn nicht, planen Sie stattdessen eine Roll-Forward-Strategie.
- Gibt es ein Backup der Datenbank, das unmittelbar vor der Migration erstellt wurde? Testen Sie, ob das Backup tatsächlich wiederhergestellt werden kann.
- Ist die Migration abwärtskompatibel mit dem aktuellen Anwendungscode? Alter Code sollte während der Migration noch funktionieren.
- Gibt es andere Dienste oder Datenbanken, die von dem Schema abhängen, das Sie ändern? Koordinieren Sie sich mit deren Teams.
- Haben Sie eine Möglichkeit zu erkennen, dass die Migration ein Problem verursacht hat, bevor Benutzer es melden? Überwachung und Alarmierung sollten eingerichtet sein.
Fazit
Ein Datenbank-Rollback ist kein einfacher "Rückgängig"-Knopf. Es ist ein risikoreicher Vorgang, der zu Datenverlust, Anwendungsfehlern und längerer Ausfallzeit führen kann. Behandeln Sie ihn mit der gleichen Vorsicht wie eine Operation: Planen Sie im Voraus, haben Sie ein Backup, und bevorzugen Sie wann immer möglich eine Vorwärtskorrektur. Das sicherste Rollback ist das, das Sie nie ausführen müssen.