Blue-Green-Datenbank-Albtraum
Blue-Green funktioniert hervorragend für zustandslose Apps. Beide Umgebungen teilen sich eine Datenbank — und unsere Schemaänderungen machten den Rollback genau dann unmöglich, als wir ihn brauchten.
Die Situation:
- Neue Version auf Green deployen
- Die neue Version führt beim Start ihre DB-Migration aus
- Traffic auf Green umschalten
- Eine Stunde später wird ein Bug entdeckt
- Wir wollen auf Blue zurückrollen...
- Aber Blue kann das neue Schema nicht lesen
Die destruktive Migration:
-- The migration that shipped with the green release
ALTER TABLE users DROP COLUMN legacy_id;
ALTER TABLE users RENAME COLUMN user_id TO id;
Der alte Code erwartet legacy_id und user_id. Beide sind weg. Der „sofortige Rollback“, der Blue-Green überhaupt erst gerechtfertigt hat, erfordert jetzt das Einspielen eines Backups oder das Handschreiben einer Rückwärtsmigration mitten im Incident — der denkbar schlechteste Zeitpunkt, um DDL zu schreiben.
Die Lösung — Expand/Contract, ausgearbeitet über drei Releases:
Release N (Expand). Die neue Spalte hinzufügen, ohne die alten anzufassen. Der Code schreibt doppelt, liest aber weiterhin die alte Spalte:
ALTER TABLE users ADD COLUMN id BIGINT;
-- backfill in batches to avoid long locks
UPDATE users SET id = user_id WHERE id IS NULL AND user_id < 100000;
-- ...repeat per batch, then:
CREATE UNIQUE INDEX CONCURRENTLY users_id_key ON users (id);
Rollback an dieser Stelle? Trivial — der alte Code sieht die neue Spalte nie.
Release N+1 (Reads migrieren). Der Code liest jetzt aus id, schreibt aber weiterhin beide Spalten. Vor dem nächsten Schritt einen Paritätscheck fahren, der die beiden Spalten vergleicht. Rollback? Ebenfalls unproblematisch — das vorherige Release schreibt noch doppelt, also veraltet keine der beiden Spalten.
Release N+2 (Contract). Erst wenn N+1 stabil gelaufen ist und die Query-Logs bestätigen, dass nichts mehr auf die alten Spalten verweist, werden sie gelöscht:
ALTER TABLE users DROP COLUMN legacy_id;
ALTER TABLE users DROP COLUMN user_id;
Der destruktive Schritt passiert weiterhin — aber zwei Releases nach der riskanten Codeänderung, wenn ein Rollback der App nicht mehr davon abhängt, dass die Spalten noch da sind.
Kernprinzip:
- Jede Schemaänderung muss rückwärtskompatibel zum laufenden Release sein
- Version N-1 muss mit Schema N funktionieren — das ist der Rollback-Vertrag
- Niemals im selben Release löschen oder umbenennen, das etwas nicht mehr verwendet
Die Konfiguration leidet zwischen Blue und Green unter demselben Shared-State-Problem — auch das haben wir erlebt, beim Blue-Green-Config-Drift.
Lektion: Die Datenbank ist der schwierigste Teil von Blue-Green, weil sie weder blau noch grün ist — sie ist geteilt. Planen Sie ihre Migrationen explizit, als Teil der Deployment-Automatisierung und nicht als nachträglich an den App-Start geschraubten Gedanken.
Incidents wie dieser sind vermeidbar. Unser AWS Managed Services-Team überwacht Kundenumgebungen 24/7 mit KI-gestütztem Monitoring und Senior Engineers auf dem Pager — damit Geschichten wie diese im Archiv bleiben.