Zero Downtime: Ein Erfahrungsbericht zur PostgreSQL-Versionsaktualisierung
Dieser Blogartikel wurde automatisch erstellt (und übersetzt). Er basiert auf dem folgenden Original, das ich für die Veröffentlichung auf diesem Blog ausgewählt habe:
A Major Postgres Upgrade with Zero Downtime.
Herausforderungen und Lösungen bei der Aktualisierung von PostgreSQL
Die Aktualisierung einer Datenbank auf eine neue Major-Version kann eine stressige Angelegenheit sein. Dieser Artikel beschreibt den Weg, den ein Team gegangen ist, um ein Aurora PostgreSQL-System ohne Ausfallzeiten zu aktualisieren. Dabei werden sowohl Fehlstarts als auch erfolgreiche Strategien beleuchtet. Das System, um das es geht, läuft auf einer moderaten Skala von unter einem Terabyte an Daten, 1,8 Millionen gelesenen Tupeln pro Sekunde und 500 geschriebenen Tupeln pro Sekunde.
Ausgangssituation
Das System besteht aus Browsern, die sich mit Sync-Servern verbinden. Diese Sync-Server verfolgen aktive Abfragen und überwachen das Write-Ahead-Log von PostgreSQL, um Änderungen an Browser zu senden. Alle Datenbanken sind unter einer Aurora PostgreSQL-Instanz gehostet.
Nach einer Open-Source-Veröffentlichung erlebte das System einen hundertfachen Anstieg des Durchsatzes. Um die Performance zu verbessern, wurde zunächst die Größe der Maschine erhöht. Dies führte zu dem Entschluss, die Abfragen zu optimieren. Dabei stellte sich heraus, dass PostgreSQL 16 viele Abfragen um 30 % oder mehr verbesserte. Dies verdeutlichte, dass allein ein Upgrade von PostgreSQL die Leistung erheblich steigern kann.
Gescheiterte Upgrade-Versuche
Es wurden verschiedene Upgrade-Methoden in Betracht gezogen, die jedoch aufgrund unterschiedlicher Probleme verworfen wurden:
- In-Place-Upgrade: Diese Option erfordert die Aktivierung des Wartungsmodus, was zu einer Ausfallzeit führt. Selbst bei einer kleineren Datenbank dauerte ein Test-Upgrade 15 Minuten, was inakzeptabel war.
- Blue-Green-Deployment: AWS verspricht hier eine minimale Ausfallzeit von einer Minute. Tests zeigten jedoch, dass aktive Replikations-Slots die Erstellung eines Blue-Green-Deployments verhinderten, da die Sync-Server das Write-Ahead-Log von PostgreSQL überwachen. Um Replikations-Slots zu deaktivieren, müssten die Sync-Server getrennt werden, was wiederum zu einer inakzeptablen Reaktionszeit führen würde.
Der manuelle Upgrade-Prozess
Nachdem die verwalteten Optionen gescheitert waren, wurde ein manuelles Upgrade durchgeführt. Dieser umfasste die folgenden Schritte:
- Erstellung einer neuen Replica mit PostgreSQL 16.
- Konfiguration der Sync-Server, um die neue Replica zu abonnieren.
- Umschalten der Schreibvorgänge auf die neue Replica.
Die Erstellung der Replica erfolgte in drei Schritten: Klonen der Datenbank, Aktualisieren des Klons und Starten der Replikation. Bei der Replikation trat ein Fehler auf, da eine benutzerdefinierte PostgreSQL-Funktion nicht gefunden wurde. Das Problem lag in den Suchpfaden. Um das Problem zu beheben, wurde ein Prefix public
zu allen Funktionsdefinitionen hinzugefügt.
Obwohl die Replica funktionierte, wurden bei einer Datenintegritätsprüfung 13 fehlende Transaktionen festgestellt. Um Datenverluste zu vermeiden, wurde ein alternativer Ansatz entwickelt:
Statt Klonen und Aktualisieren wurde mit einer frischen Datenbank mit PostgreSQL 16 begonnen und von Grund auf neu repliziert.
Dieser Prozess umfasste sieben Schritte:
- Erstellung einer neuen Aurora PostgreSQL-Datenbank mit PostgreSQL 16.
- Extrahieren des Schemas aus der alten Datenbank.
- Importieren des Schemas in die neue Datenbank.
- Erstellen einer Publication für alle Tabellen in der alten Datenbank.
- Erstellen einer Subscription mit
copy_data = true
in der neuen Datenbank. - Bestätigen, dass keine Datenverluste auftreten.
- Ausführen von
vacuum analyze
.
Dieser Ansatz war erfolgreich und führte zu einer Replica mit PostgreSQL 16.
Umschalten der Subscriptions und Schreibvorgänge
Um die Sync-Server auf die neue Replica umzustellen, wurde eine Variable next-database-url
hinzugefügt. Nach dem Deployment replizierten die Sync-Server von der neuen Replica.
Für das Umschalten der Schreibvorgänge mussten zwei Regeln beachtet werden:
- Die neue Replica muss auf dem neuesten Stand sein.
- Alle neuen Schreibvorgänge müssen an die neue Replica gehen.
Der einfachste Weg wäre gewesen, alle Schreibvorgänge zu stoppen, bis die Replica aufgeholt hat. Da jedoch eine feinere Kontrolle über die Verbindungen möglich war, wurde ein Algorithmus für Null-Downtime implementiert:
- Pausieren aller neuen Transaktionen.
- Warten, bis alle aktiven Transaktionen abgeschlossen sind und die neue Replica aufgeholt hat.
- Fortsetzen aller Transaktionen, die nun an die neue Replica gehen.
Bei Tests traten erneut Fehler auf, diesmal Unique-Constraint-Verletzungen. Dies lag daran, dass PostgreSQL keine Sequenzdaten repliziert. Um das Problem zu beheben, wurden die Sequenzen in der Failover-Funktion inkrementiert.
Nach einer erfolgreichen Generalprobe wurde der Failover in der Produktion durchgeführt. Nach einer kurzen Pause von 3,5 Sekunden war der Prozess abgeschlossen, ohne dass Benutzer etwas bemerkten.
Lessons Learned
- Neuere PostgreSQL-Versionen können die Leistung verbessern.
- Führen Sie vor der Produktion immer eine vollständige Generalprobe durch.
- Wenn 15 Minuten Downtime akzeptabel sind, führen Sie ein In-Place-Upgrade durch.
- Wenn Sie keine aktiven Replikations-Slots haben und eine Minute Downtime akzeptabel ist, versuchen Sie ein Blue-Green-Deployment.
- Bei einem manuellen Upgrade:
- Erstellen Sie eine Replica von Grund auf neu.
- Überprüfen Sie den Suchpfad für benutzerdefinierte Funktionen.
- Führen Sie Integritätsprüfungen durch, um Datenverluste zu vermeiden.
- Nutzen Sie Algorithmen zur Minimierung von Downtime.
Obwohl der beschriebene Failover in dieser Größenordnung funktionierte, wird er in Zukunft wahrscheinlich nicht mehr ausreichen. Geplant sind Verbesserungen, die das Pausieren der Lesezugriffe vermeiden und einen Zwei-Phasen-Commit implementieren.