Behebung des strukturellen Leistungsengpasses in verwaltetem Postgres
von David Wein und Vlad Lazar
In einem Lakebase sind Compute und Storage per Design getrennt. Während diese Trennung ursprünglich für operative Flexibilität, einschließlich Skalierung, Branching und sofortiger Wiederherstellung, entwickelt wurde, eröffnet sie auch eine massive Leistungsgrenze.
Durch die Entkopplung dieser Ebenen können wir Arbeit von Ihrem Postgres-Compute auf unseren verteilten Speicher auslagern, auf eine Weise, die in traditionellen, monolithischen Postgres-Bereitstellungen strukturell unmöglich ist. In diesem Beitrag untersuchen wir, wie wir diesen architektonischen Vorteil genutzt haben, um einen seit einem Jahrzehnt bestehenden Postgres-Engpass zu beseitigen und den Postgres-Schreibdurchsatz um das 5-fache zu verbessern, während wir die Lese-Tail-Latenzen um das 2-fache und den WAL-Verkehr um 94 % reduzierten.
Um zu verstehen, wie wir eine 5-fache Verbesserung der verwalteten Postgres-Leistung erzielt haben, müssen wir uns ansehen, wie traditionelles Postgres die Haltbarkeit handhabt.
In Postgres wird jede Datenbankänderung zuerst in einem sequenziellen Protokoll (dem Write-Ahead Log, oder WAL) gespeichert, um sicherzustellen, dass keine Daten bei einem Absturz verloren gehen. Um die Wiederherstellungszeiten nach einem Absturz schnell zu halten, führt Postgres periodisch eine Hintergrundbereinigungsaktion namens „Checkpoint“ durch. Im Gegensatz zu einem Snapshot ist ein Checkpoint lediglich eine Meilensteinmarkierung im Protokoll. Während eines Checkpoints nimmt Postgres alle modifizierten Daten, die sich derzeit im Speicher befinden (verwaltet in 8-KB-Blöcken, sogenannten „Pages“), und leert sie auf die Hauptfestplatte bis zu einem bestimmten Punkt im Protokoll. Wenn ein Absturz auftritt, stellt Postgres Ihre Daten wieder her, indem es am Checkpoint-Meilenstein beginnt und die jüngsten WAL-Protokolle über die Festplatte wiedergibt.
Es gibt jedoch ein Risiko: Wenn der Server genau dann abstürzt, wenn eine 8-KB-Seite auf die Festplatte geschrieben wird, wird die Seite möglicherweise nur teilweise geschrieben, was zu einer beschädigten „Torn Page“ führt. Wenn Postgres versucht, eine winzige Protokollaktualisierung über eine beschädigte Seite wiederzugeben, sind die Daten dauerhaft ruiniert. Um dies zu beheben, muss Postgres sicherstellen, dass es sich niemals auf eine beschädigte Festplatte zur Wiederherstellung verlässt.
Dies geschieht mithilfe von „Full Page Write“ (FPW). Wenn eine Seite zum ersten Mal *nach* einem Checkpoint-Meilenstein geändert wird, protokolliert Postgres nicht nur die winzige Änderung, sondern kopiert die *gesamte* 8-KB-Seite in den WAL. Wenn ein Absturz auftritt und die Festplattenseite beschädigt ist, ignoriert Postgres die beschädigte Festplatte, holt sich das makellose 8-KB-Backup aus dem WAL und verwendet es als perfekten Ausgangspunkt, um den Rest der Protokolle wiederzugeben. Dies garantiert zwar absolute Sicherheit, ist aber kostspielig: Bei schreibintensiven Anwendungen kann das Protokollieren ganzer 8-KB-Seiten das Protokollvolumen um bis zu das 15-fache erhöhen und wird oft zum größten Leistungsengpass des Systems.
In der Lakebase-Architektur ist Ihr Compute zustandslos. Es stützt sich nicht auf ein lokales Datenverzeichnis. Stattdessen streamt es WAL an ein Paxos-basiertes Quorum von Safekeepers.
Da keine lokale Festplattenseite beschädigt werden kann, existiert der Fehlerfall, für den FPW entwickelt wurde, einfach nicht. Das naive Ausschalten von FPW schafft jedoch ein sekundäres Problem: die Leseleistung. Ohne diese periodischen vollständigen Seitenbilder im Protokoll müsste die Speicherschicht eine unendlich lange Kette kleiner Deltas wiedergeben, um eine Seite für eine Leseanforderung zu rekonstruieren. Was einst eine begrenzte Wiedergabe von O(Checkpoint-Frequenz) war, wird zu einer unbegrenzten Kette, was zu einem Anstieg der Leselatenz und des Ressourcenverbrauchs führt.
Wir haben dies gelöst, indem wir die Intelligenz vom Compute-Knoten in die Speicherschicht verlagert haben. Wir nennen dies „Image Generation Pushdown“.
Wenn der Postgres-Compute eine Seite vom Speicher anfordert, rekonstruiert der Pageserver (eine Komponente des Lakebase-verteilten Speichersystems) diese, indem er das aktuellste materialisierte Bild dieser Seite findet und alle WAL-Deltas darüber wiedergibt. Die vollständigen Seitenbilder, die der Compute früher in den WAL eingebettet hat, dienten als periodische Rücksetzpunkte in dieser Delta-Kette und hielten die Kette auf natürliche Weise begrenzt und die Lesevorgänge schnell. Eine detailliertere Behandlung dieses Mechanismus finden Sie unter Deep Dive in das Neon Storage Engine.
Wenn Full Page Writes deaktiviert sind, verschwinden diese Rücksetzpunkte. Ohne zusätzliche Intelligenz im verteilten Speichersystem könnte eine häufig aktualisierte Seite eine lange Kette kleiner Deltas ohne dazwischenliegendes Bild ansammeln. Das Ergebnis wäre ein unerwünschter Anstieg der Leselatenz und des Ressourcenverbrauchs, da der Pageserver die gesamte Kette wiedergeben müsste, um eine Lesung zu bedienen, was die Latenz und den Ressourcenverbrauch erhöht.
Um dieses Problem zu vermeiden, haben wir die Verantwortung für die Bildgenerierung vom WAL-Stream des Compute in die Speicherschicht verlagert, wodurch das begrenzte Leseverhalten des Speichers erhalten bleibt und gleichzeitig der WAL-Overhead beim Compute entfällt. Der Pageserver generiert nun vollständige Seitenbilder, wenn eine Seite mehr Delta-Datensätze angesammelt hat als ein konfigurierter Schwellenwert ohne dazwischenliegendes Bild. Dies ist ein natürlich besserer Ansatz, da die Entscheidung zur Generierung eines neuen Bildes auf der tatsächlichen Anzahl von Änderungen an einer Seite basiert und nicht auf dem nicht damit zusammenhängenden Postgres-Checkpoint-Prozess.
Hier ist, warum dies für die Leistung erheblich besser ist:
Wir haben diese Optimierung mit HammerDB TPROC-C (ein TPC-C-abgeleitetes OLTP-Benchmark) bewertet und die Ergebnisse mit realen Produktions-Workloads validiert.
Der Durchsatz wird in neuen Bestellungen pro Minute (NOPM) gemessen. Die Gewinne skalieren dramatisch mit der Größe der Compute-Instanz:
Compute-Größe | Vorher (NOPM) | Nachher (NOPM) | Durchsatzgewinn |
4-vCPU | 78.876 | 94.891 | 20 % |
16-vCPU | 95.832 | 269.189 | 2,8x |
32-vCPU | 95.686 | 439.300 | 4,5x+ |

Bei 32 vCPUs überstieg die Verbesserung 450 %.
Mit auf dem Compute generierten Full Page Images generiert jede Transaktion durchschnittlich 58 KB WAL. Mit nach unten verschobener Bildgenerierung sinkt dies auf unter 4 KB – eine Reduzierung um 94 %. Der Durchsatzgewinn ergibt sich direkt: weniger WAL bedeutet weniger Konflikte auf dem Schreibpfad, weniger verbrauchte Netzwerkbandbreite und weniger Arbeit für die Speicherschicht zur Aufnahme.

Durch die Beseitigung des FPW-Engpasses von Postgres konnten wir den Durchsatz linear mit den Compute-Ressourcen skalieren. Dies ist etwas, das monolithisches Postgres unter hoher Schreiblast nur schwer bewältigen kann.
In einer Produktionsumgebung für ein hochkarätiges 56-vCPU-Projekt reduzierte die Aktivierung von Image Pushdown die Steady-State-WAL-Generierung von 30 MB/s auf nur 1 MB/s.
Diese Volumenreduzierung korrelierte direkt mit einem erhöhten Transaktionsdurchsatz während der täglichen Spitzenlastzeiten.
Dies half nicht nur beim Schreiben. Durch die Optimierung der Delta-Chains sank die Anzahl der WAL-Datensätze, die pro Lesevorgang angewendet werden müssen, erheblich. Wir sahen, dass die p99-Leselatenzen um 30 % bis 50 % und die p50-Latenzen um etwa 30 % sanken.
Wenn wir weiter hinauszoomen, auf die regionale Ebene, sahen wir nach der Aktivierung, dass die Gesamtmenge an WAL, die von Computes generiert wurde, um bis zu 4x zurückging. Die P99-Latenz von Lesevorgängen aus der Storage-Engine verbesserte sich um bis zu 3x und wurde wesentlich stabiler.
Bei datenintensiven synchronisierten Tabellen war die Auswirkung sofort spürbar. Ein Kunde sah, wie der Ingestion-Durchsatz von 17.000 Zeilen pro Sekunde auf 62.000 Zeilen pro Sekunde sprang, was einer 3-fachen Steigerung entspricht, einfach durch die Aktivierung von Image Pushdown.
Seit Ende März haben wir dies in unserer gesamten Flotte eingeführt. Es ist jetzt für alle Lakebase Serverless- und Neon-Datenbanken weltweit aktiv.
Die Änderung wurde über unsere Control Plane und unser Speichersystem auf laufende Computes angewendet, was den Übergang automatisch koordinierte. Dies wurde unter Verwendung des vorhandenen Postgres XLOG_FPW_CHANGE WAL-Mechanismus für Datensätze erreicht, was bedeutet, dass für unsere Kunden keine Neustarts oder Unterbrechungen erforderlich waren.
Die Lakebase-Architektur wurde für Flexibilität gebaut, aber sie wurde für Leistung entwickelt. Das Herunterdrücken von Full Page Writes ist Teil einer systematischen Anstrengung, die Vorteile der Trennung von Speicher und Compute zu nutzen.
So wie wir Cache-Prewarming für Zero-Downtime-Patching eingeführt haben, verlagern wir weiterhin rechenintensive Aufgaben von Ihren Transaktionen in unseren skalierbaren Hintergrundspeicher-Stack. Die Postgres-Schreibsteuer ist offiziell Geschichte.
(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag
Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.