Datenbank-Migrationen testen, bevor sie in Produktion gehen

Sie haben ein Migrationsskript geschrieben. Es sieht korrekt aus. Die Syntax ist gültig. Die Logik scheint richtig. Sie führen es gegen Ihre lokale Datenbank aus, und es funktioniert einwandfrei. Dann deployen Sie es in die Produktion, und alles bricht zusammen.

Die Tabelle hatte Millionen von Zeilen. Ihre lokale Datenbank hatte zwölf. Die Migration fügte eine NOT-NULL-Spalte hinzu, aber in der Produktion gab es vorhandene NULL-Werte, von denen Sie nichts wussten. Das ALTER TABLE sperrte Schreibzugriffe für fünfzehn Minuten während der Hauptlastzeit.

Dieses Szenario ist nicht selten. Es passiert, weil die Umgebung, in der Sie Ihre Migration testen, nicht der Umgebung entspricht, in der sie tatsächlich ausgeführt wird. Eine Migration, die auf einer leeren oder nicht übereinstimmenden Datenbank besteht, erzeugt falsche Sicherheit. Die Lösung ist nicht, auf Ihrem lokalen Rechner sorgfältiger zu testen. Die Lösung ist, eine Testumgebung zu schaffen, die die Produktionsrealität widerspiegelt.

Warum ein übereinstimmendes Schema wichtig ist

Ein Migrationsskript basiert auf Annahmen. Es nimmt an, dass bestimmte Spalten existieren, bestimmte Indizes vorhanden sind, bestimmte Constraints eingerichtet sind. Wenn Ihre Testdatenbank ein anderes Schema hat, testen Sie gegen andere Annahmen.

Betrachten Sie eine Migration, die eine NOT-NULL-Spalte hinzufügt. In einer Testdatenbank mit einer leeren Tabelle läuft die Migration sofort. In der Produktion hat die Tabelle Zeilen mit NULL-Werten in dieser Spalte. Die Migration schlägt fehl, und Sie haben einen Produktionsvorfall.

Der zuverlässigste Weg, Schemas abzugleichen, ist ein Schema-Dump aus der Produktion und die Wiederherstellung in Ihrer Testumgebung. Das gibt Ihnen die exakten Tabellenstrukturen, Indizes, Constraints und Datentypen, die in der Produktion existieren. Sie müssen nicht mehr raten, ob Ihr Testschema der Realität entspricht.

Hier ein konkretes Beispiel mit PostgreSQL:

# Nur das Schema (keine Daten) aus der Produktion dumpen
pg_dump --schema-only --no-owner --no-ack production_db > schema.sql

# Schema in die Testdatenbank einspielen
psql test_db < schema.sql

Daten, die echte Probleme aufdecken

Eine leere Tabelle oder eine Tabelle mit zufälligen Testdaten wird Randfälle nicht offenlegen. Migrationsfehler entstehen oft durch Daten, die in der Produktion existieren, aber nicht in Ihrem Testsatz.

Wenn Ihre Migration einen Spaltentyp ändert, sollten Ihre Testdaten Randwerte enthalten: lange Zeichenketten, Dezimalzahlen mit vielen Nachkommastellen, NULL-Werte in dieser Spalte. Wenn Ihre Migration einen eindeutigen Constraint hinzufügt, sollten Ihre Testdaten doppelte Zeilen enthalten, die diesen Constraint verletzen. Wenn Ihre Migration eine Spalte entfernt, sollten Ihre Testdaten Abfragen enthalten, die diese Spalte noch referenzieren.

Sie müssen nicht den gesamten Produktionsdatensatz kopieren. Für eine Tabelle mit Millionen von Zeilen reichen ein paar tausend gut ausgewählte Zeilen aus, um der Datenbank-Engine einen realistischen Ausführungsplan zu entlocken. Das Ziel ist nicht, das Produktionsvolumen zu replizieren. Das Ziel ist, die Datenmuster zu replizieren, die dazu führen könnten, dass sich die Migration anders verhält.

Dry-Run als Sicherheitsnetz

Ein Dry-Run führt das Migrations-SQL aus, ohne die Datenbank dauerhaft zu verändern. Einige Migrationstools haben einen integrierten Dry-Run-Modus. Falls Ihres nicht, können Sie die Migration in eine Transaktion packen und am Ende zurücksetzen.

Der Zweck eines Dry-Runs ist nicht zu bestätigen, dass die Migration erfolgreich ist. Es geht darum, Warnungen, Fehler und Änderungen im Ausführungsplan zu sehen, die auf Probleme hinweisen könnten. Eine Migration, die auf einer kleinen Tabelle einwandfrei läuft, könnte bei einem realistischen Schema eine Warnung wegen eines Full-Table-Scans anzeigen. Ein ALTER TABLE auf einer großen Tabelle könnte eine geschätzte Ausführungszeit zeigen, die für Ihr Wartungsfenster inakzeptabel ist.

Nach dem Dry-Run überprüfen Sie die Ausgabe manuell oder durch automatisierte Checks. Achten Sie auf Operationen, die Tabellen für längere Zeit sperren könnten. Achten Sie auf Abfragen, die die Performance verschlechtern könnten. Achten Sie auf unerwartetes Verhalten, das bei lokalen Tests nicht aufgetreten ist.

Simulieren einer leichten Last während der Migration

Manche Migrationen sind auf einer ruhenden Datenbank sicher, verursachen aber unter realem Traffic Probleme. Ein ALTER TABLE, das eine Sperre erwirbt, könnte in Sekunden abgeschlossen sein, wenn niemand sonst die Tabelle verwendet. Unter Produktionslast könnte dieselbe Sperre zu Query-Timeout und Anwendungsfehlern führen.

Sie brauchen keinen vollständigen Lasttest. Ein einfaches Skript, das während der Migration SELECT- und INSERT-Abfragen gegen die betroffenen Tabellen ausführt, reicht aus. Wenn diese simulierten Abfragen fehlschlagen oder ein Timeout auftritt, haben Sie ein Problem gefunden, das Produktionsnutzer getroffen hätte.

Führen Sie diese Simulation während der Dry-Run-Phase durch. Wenn die Migration unter leichter Last Deadlocks oder übermäßige Wartezeiten verursacht, müssen Sie Ihren Ansatz überdenken. Vielleicht müssen Sie eine weniger störende Sperrstrategie verwenden. Vielleicht müssen Sie die Migration in kleinere Schritte aufteilen. Vielleicht müssen Sie sie in ein Fenster mit geringerem Traffic verschieben.

Automatisierung der Testumgebung

Das manuelle Einrichten einer Testumgebung für jede Migration ist langsam und fehleranfällig. Der bessere Ansatz ist, sie als Teil Ihrer CI-Pipeline zu automatisieren.

Wenn eine neue Migration committed wird, erstellt die Pipeline eine Testumgebung aus einem Produktionsschema-Snapshot. Sie lädt die relevanten Testdaten. Sie führt den Dry-Run durch. Sie simuliert leichte Last. Dann zerstört sie die Umgebung.

Diese Automatisierung stellt sicher, dass jede Migration gegen eine konsistente Baseline getestet wird. Niemand kann den Test überspringen, weil er es eilig hatte. Niemand kann behaupten, der Test sei bestanden, weil ein anderes Schema verwendet wurde. Die Pipeline erzwingt jedes Mal die gleichen Bedingungen.

Eine praktische Checkliste

Bevor Sie eine Migration in der Produktion ausführen, stellen Sie sicher, dass diese Bedingungen erfüllt sind:

  • Das Testschema stimmt exakt mit dem Produktionsschema überein
  • Die Testdaten enthalten Randfälle, die für die Migration relevant sind
  • Der Dry-Run wurde ohne unerwartete Warnungen oder Fehler abgeschlossen
  • Die Simulation einer leichten Last hat keine Fehler oder Timeouts verursacht
  • Die Testumgebung wurde aus einem aktuellen Produktions-Snapshot erstellt

Was das für Ihre Pipeline bedeutet

Datenbank-Migrationen sind kein Anwendungscode. Sie können nicht einfach deployen und beobachten. Eine fehlgeschlagene Migration kann Daten korrumpieren, Tabellen sperren und längere Ausfallzeiten verursachen. Die Kosten einer schlechten Migration sind viel höher als die Kosten eines schlechten Application-Releases.

Das Testen von Migrationen in einer realistischen Umgebung ist keine Option. Es ist der Unterschied zwischen dem Wissen, dass Ihre Migration funktionieren wird, und der Hoffnung, dass sie funktionieren wird. Die Umgebung, die Sie zum Testen aufbauen, muss nicht teuer oder komplex sein. Sie muss repräsentativ sein.

Beginnen Sie mit einem Schema-Dump aus der Produktion. Fügen Sie gezielte Testdaten hinzu. Führen Sie Dry-Runs durch. Simulieren Sie leichte Last. Automatisieren Sie den gesamten Prozess. Ihre Produktionsdatenbank wird es Ihnen danken.