Direkt zum Hauptinhalt
Data Engineering

Autoskalierung von Lakebase Postgres

Ein tiefer Einblick, wie wir Postgres in Echtzeit skalieren

von Carlota Soto

  • Architektonische Anforderungen für Autoscaling
  • Wann die Kapazität hoch- und herunterskaliert werden sollte
  • Wie die Kapazität angepasst werden kann, ohne PostgreSQL zu stoppen

Die Größe einer Datenbankinstanz zu wählen, bevor man die Arbeitslast kennt, ist ein veraltetes Entwurfsmuster. Der Prozess ist im Allgemeinen ungenau und fühlt sich wie eine große Verschwendung von Rechenleistung an, besonders jetzt, da Rechenleistung zu einem Luxusgut wird.

Lakebase Postgres erspart Ihnen dank Autoscaling die Dimensionierung komplett. Die schnelle Reaktion des Autoscalings basiert auf der direkten Größenänderung von VMs (In-Place VM Resizing) und einem Algorithmus, der CPU, Arbeitsspeicher und das Working Set der Datenbank überwacht.

image9.png

So sieht Autoscaling für eine beliebige Stichprobe von Lakebase Postgres-Datenbanken aus. Bitte beachten Sie, dass dies nur eine Stunde darstellt.

Die architektonische Voraussetzung

Das traditionelle Postgres läuft als zustandsbehafteter (stateful) Prozess, der an eine Maschine und deren Festplatten gebunden ist. Das Ersetzen oder Ändern der Größe dieser Maschine ist ein Datenbankvorgang, da die Maschine sowohl für die Ausführung als auch für den dauerhaften Zustand zuständig ist. Die Lakebase Postgres-Architektur trennt diese Aufgaben jedoch:

  • Die Compute-Ebene führt Postgres aus und verarbeitet Abfragen. Sie nutzt RAM und lokales NVMe für den Zugriff mit geringer Latenz und besitzt keinen dauerhaften Zustand.
  • Die Storage-Ebene sorgt für Dauerhaftigkeit und Historie. WAL wird von Safekeepern auf SSDs repliziert, Pageserver (ebenfalls SSDs) rekonstruieren Seitenversionen, und der Objektspeicher bewahrt die langfristigen, unveränderlichen Daten auf. (Dieser Blogbeitrag konzentriert sich auf Compute, aber wir haben einen detaillierten Einblick in den Storage-Teil geschrieben, falls Sie daran interessiert sind.)

Ein Compute-Knoten kann daher gestartet, gestoppt, verschoben oder in der Größe geändert werden, ohne die darunter liegende Datenbank zu verschieben. Dies ist eine wesentliche Grundlage.

image8.png

Bei der Implementierung von Autoscaling gibt es zwei Aspekte: Erstens muss bestimmt werden, wann die Kapazität nach oben oder unten angepasst werden soll, und zweitens, wie dies ohne Unterbrechung von Postgres geschehen kann.

Gehen wir der Reihe nach auf beide Punkte ein.

Teil I: Der Algorithmus

Die drei Autoscaling-Signale

Um zu ermitteln, wann eine Größenänderung erforderlich ist, verfolgt der Autoscaling-Algorithmus von Lakebase Postgres drei Signale, wobei jedes Signal seine eigene Compute-Zielgröße definiert:

  1. CPU-Auslastung: cpuGoalCU
  2. Arbeitsspeichernutzung: memGoalCU
  3. Größe des Compute-Cache-Working-Sets: lfcGoalCU

Das endgültige Skalierungsziel ist der größte der drei Werte, begrenzt auf die vom Benutzer für diese Datenbank konfigurierten minimalen und maximalen Compute-Größen (die Autoscaling-Limits):

CPU (cpuGoalCU)

Die CPU ist das unkomplizierteste der drei Signale. Der Algorithmus überwacht genau, wie stark der Prozessor ausgelastet ist:

  • Alle fünf Sekunden liest der autoscaler-agent die durchschnittliche einminütige CPU-Auslastung der VM aus.
  • Das CPU-Ziel besteht darin, diese Auslastung bei oder unter 90 % der verfügbaren CPU-Kapazität zu halten.
  • Wenn die Auslastung über dieses Ziel steigt, erhöht sich cpuGoalCU. Wenn die dauerhafte Auslastung sinkt, sinkt auch das Ziel.

Die Verwendung eines einminütigen Durchschnitts filtert sehr kurze Schwankungen heraus und reagiert dennoch auf signifikante Änderungen der Nachfrage. Das Abfrageintervall von fünf Sekunden ermöglicht es dem System, das Ziel anzupassen, wenn sich dieser Durchschnitt ändert.

Die CPU allein reicht jedoch nicht aus, um Postgres korrekt zu skalieren. Eine Abfrage, die auf Daten aus dem Netzwerk wartet, kann eine geringe CPU-Auslastung aufweisen, obwohl die Leistung schlecht ist. Der Algorithmus muss daher auch den Druck auf Arbeitsspeicher und Cache berücksichtigen.

Arbeitsspeicher (memGoalCU)

Der Arbeitsspeicher verhält sich bei Fehlern anders als die CPU. Wenn der Bedarf kurzzeitig die verfügbare CPU übersteigt, werden Abfragen langsamer. Wenn Postgres jedoch mehr Arbeitsspeicher zuweist, als die VM zur Verfügung hat, kann der Kernel Prozesse beenden. Der Autoscaler benötigt daher ein viel schnelleres Signal für Speicherengpässe als für die CPU-Auslastung.

Das System überwacht den Arbeitsspeicher daher in zwei Intervallen:

  • Alle fünf Sekunden liest der autoscaler-agent die gesamten Arbeitsspeicher-Metriken der VM aus.
  • Alle 100 Millisekunden überprüft der vm-monitor den von Postgres verwendeten Arbeitsspeicher.

Das Arbeitsspeicherziel hält die Nutzung unter 75 % des zugewiesenen RAMs. Dieser Puffer gibt dem System Raum, um auf neue Zuweisungen zu reagieren, und lässt genügend Speicher für das Gastbetriebssystem und andere Prozesse übrig.

Der vm-monitor prüft jede vorgeschlagene Herunterskalierung. Der Arbeitsspeicher kann nicht reduziert werden, wenn die laufenden Prozesse dadurch nicht mehr genügend Platz hätten.

Ein kleiner Rückblick: Dieser Abfrage-Ansatz ersetzte ein früheres Design, das auf dem cgroup-memory.high-Event basierte. Das Überschreiten von memory.high veranlasste Linux dazu, Arbeitsspeicher freizugeben und die Prozesse innerhalb der cgroup zu drosseln. Polling erwies sich als berechenbarer und stabiler, während es dem System dennoch alle 100 Millisekunden einen Einblick in den Postgres-Speicher ermöglichte.

Der Compute-Cache (lfcGoalCU)

Das dritte Signal misst, ob die aktiven Daten der Arbeitslast nahe genug an Postgres liegen. Kurz gesagt funktioniert das so:

Lakebase Postgres trennt Storage und Compute. Wenn eine Seite lokal nicht verfügbar ist, fordert die Compute-Instanz sie vom Pageserver an. Die zurückgegebene Seite wird für nachfolgende Lesevorgänge zwischengespeichert. Der Compute-Cache, den wir ursprünglich Local File Cache oder (LFC) nannten, ist ein festplattenbasierter Cache, der so dimensioniert ist, dass er in den Kernel-Page-Cache passt. Er fungiert als in der Größe anpassbare Erweiterung der Shared Buffers von Postgres. Wenn eine Compute-Instanz wächst, erweitert der vm-monitor den Cache, um einen Teil des hinzugefügten Speichers zu nutzen.

Bei vielen OLTP-Arbeitslasten ändert sich die Leistung drastisch, sobald das Working Set in den lokalen Speicher passt. Dies offenbart einen blinden Fleck beim reinen CPU-Autoscaling: Cache-Misses führen dazu, dass Abfragen auf Netzwerkanfragen warten müssen, was die CPU-Auslastung senkt. Das System sieht daher möglicherweise genau in dem Moment eine geringe CPU-Auslastung, in dem ein größerer Cache die Leistung verbessern würde. In Lakebase Postgres gibt es daher ein drittes Autoscaling-Signal, das das Postgres-Working-Set direkt schätzt.

Dies ist der interessanteste Teil des Algorithmus. Sehen wir uns also an, wie diese Schätzung funktioniert.

Genauer betrachtet: Wie wir das Postgres-Working-Set schätzen

Das Working Set einer Arbeitslast ist die Menge an Datenbank- und Indexseiten, auf die über einen bestimmten Zeitraum wiederholt zugegriffen wird. Jede einzelne Seite für das Autoscaling exakt zu zählen, würde zu viel Speicher erfordern. Die klassische Lösung hierfür ist die Verwendung von HyperLogLog, einem probabilistischen Kardinalitätsschätzer, der die Anzahl eindeutiger Elemente in einer Menge mit einer geringen, festen Speichermenge schätzen kann.

Bei jedem Postgres-Seitenzugriff führt eine standardmäßige HyperLogLog-Implementierung folgende Schritte aus:

  1. Hasht den Seitenbezeichner.
  2. Verwendet die ersten Bits des Hashs, um ein Register auszuwählen.
  3. Zählt die führenden Nullen in den verbleibenden Bits.
  4. Aktualisiert das ausgewählte Register, wenn dieser beobachtete Wert seinen vorherigen Wert übersteigt.

Die Verteilung dieser Registerwerte liefert eine Schätzung darüber, wie viele eindeutige Seiten beobachtet wurden.

image10.png

Es gibt jedoch ein Problem bei der einfachen Verwendung von HyperLogLog für das Autoscaling: Ein Standard-HyperLogLog wächst nur. Sobald ein Register einen Wert beobachtet hat, kann es nicht mehr feststellen, welches Element diesen erzeugt hat oder wann dieses Element zuletzt gesehen wurde.

Dadurch eignet es sich gut zur Beantwortung der Frage: „Auf wie viele eindeutige Seiten hat diese Compute-Instanz seit dem Start von Postgres zugegriffen?“ Autoscaling benötigt jedoch eine andere Antwort, die eher lautet: „Wie viele eindeutige Seiten gehören zu der aktuell ausgeführten Arbeitslast?“

Ohne eine zeitliche Begrenzung würden ein alter Import oder eine analytische Abfrage in der Schätzung verbleiben und die Compute-Instanz noch lange nach Abschluss dieser Arbeit überdimensioniert halten. Daher haben wir geändert, was die HyperLogLog-Register speichern.

HyperLogLog um eine Zeitkomponente erweitern

So funktioniert es in Lakebase Postgres tatsächlich:

Anstatt ein Bit zu setzen, wenn ein Hash beobachtet wird, speichert der Schätzer den aktuellen Zeitstempel an dieser Position. Um die Kardinalität seit dem Zeitpunkt T zu schätzen, behandelt er Positionen, die nach T aktualisiert wurden, als gesetzt und ältere Positionen als nicht gesetzt.

image6.png

Modifiziertes HyperLogLog in der automatischen Skalierung von Lakebase Postgres.

Dies liefert eine Schätzung für jedes Zeitfenster, das in der Gegenwart endet, einschließlich

  • Eindeutige Seiten, auf die in der letzten Minute zugegriffen wurde
  • Eindeutige Seiten, auf die in den letzten fünf Minuten zugegriffen wurde
  • Eindeutige Seiten, auf die in der letzten Stunde zugegriffen wurde

Um zum Algorithmus zurückzukehren: So funktioniert die Granularität tatsächlich: Alle 20 Sekunden erfasst der autoscaler-agent Schätzungen des Arbeitssatzes für Zeitfenster von einer bis 60 Minuten.

Aber das ist noch nicht alles. Wie Sie sicher bemerken, ist dies ein großes Zeitfenster. Wie wählen wir es eigentlich aus?

Auswahl des Arbeitssatz-Zeitfensters

Das Problem ist folgendes: Es gibt kein universelles Zeitfenster, das den aktuellen Arbeitssatz einer Datenbank beschreibt. Wenn wir ein kurzes Fenster wählen, reagiert die Engine zur automatischen Skalierung schnell, wenn eine Arbeitslast endet, verwirft aber den Cache zwischen Lastspitzen zu aggressiv. Wenn wir ein langes Fenster wählen, schützt der Algorithmus zwar den Cache, hält aber auch Speicher für Arbeit reserviert, die gar nicht mehr läuft.

Der Algorithmus löst dies, indem er untersucht, wie sich der Arbeitssatz im Laufe der Zeit verändert. Beispiel: Bei einer gleichmäßigen Arbeitslast wächst die geschätzte Anzahl der Seiten anfangs und flacht dann ab. Eine Verlängerung des Fensters bringt zwar mehr Zeit, aber es kommen nur wenige neue Seiten hinzu, da immer wieder auf denselben Arbeitssatz zugegriffen wird.

image5.png

Betrachten wir nun eine hohe Arbeitslast, die vor Kurzem geendet hat. Kurze Fenster enthalten nur die aktuelle, geringere Arbeitslast. Sobald das Fenster jedoch weit genug in die Vergangenheit reicht, um die vorherige Arbeitslast einzuschließen, springt die Schätzung nach oben. Der Algorithmus sucht nach diesem Sprung, der das Ende des aktuellen Plateaus markiert.

image4.png

Kurz gesagt:

Die Implementierung beginnt ihre Suche nach fünf Minuten. Dies verhindert, dass die Rechenressourcen bei einer kurzen Pause sofort schrumpfen und bei der nächsten Lastspitze wieder anwachsen müssen. Wenn der Algorithmus jedoch keinen starken Anstieg findet, verwendet er die 60-Minuten-Schätzung – das ist das erwartete Ergebnis für eine stabile Arbeitslast, deren Arbeitssatz die ganze Stunde über aktiv bleibt.

image1.png

Prognose des Cache-Wachstums

Es gibt noch einen letzten Aspekt. Die Messung des aktuellen Arbeitssatzes kommt etwas zu spät: Angenommen, eine Arbeitslast beginnt mit dem Scannen eines neuen Seitensatzes. Wenn der Cache der Rechenressourcen erst wächst, nachdem diese Seiten gelesen wurden, wurden frühere Seiten möglicherweise bereits verworfen, um Platz für spätere zu machen. Der Cache muss dann dieselben Daten erneut abrufen.

Daher prognostiziert der Algorithmus auch das Wachstum des Arbeitssatzes im Voraus. Er untersucht, wie die Schätzung von einem Zeitraum zum nächsten ansteigt, und weist genügend Cache für den Arbeitssatz zu, der für das nächste Kontrollintervall erwartet wird.

Da Cache-Metriken alle 20 Sekunden abgerufen werden, deckt die Prognose nur einen Bruchteil einer Minute ab. Längere Prognosen würden zwar früher reagieren, aber sie würden auch kurze Spitzen verstärken und die Rechenressourcen zum Schwingen bringen.

image2.png

Die prognostizierte Größe wird (endlich!) zu lfcGoalCU. Und das algorithmische Ziel besteht darin, den Arbeitssatz in den für den Cache verfügbaren Speicher einzupassen, bis zu 75 % des RAMs der Rechenressource.

Teil II: Größenänderung der laufenden Rechenressource

Zusammenfassend war das Skalierungsziel:

Diese drei Signale teilen dem System mit, welche Größe angestrebt werden soll. Die Anwendung dieser Größe bedeutet, CPU und Arbeitsspeicher auf einer laufenden VM ohne Unterbrechung von Postgres zu ändern.

Jede Postgres-Instanz in Lakebase Postgres läuft in einer eigenen virtuellen Maschine in einem Kubernetes-Cluster. Wir verwenden VMs, weil sie eine starke Isolationsgrenze bieten und es im Gegensatz zu einer herkömmlichen Container-Zuweisung ermöglichen, CPU und Arbeitsspeicher einer laufenden Gast-VM hinzuzufügen oder zu entziehen.

Vier Komponenten koordinieren jede Größenänderung der Rechenressourcen:

  1. Der autoscaler-agent läuft auf jedem Kubernetes-Knoten. Er sammelt Metriken von den Postgres-VMs auf diesem Knoten, berechnet die Zielgrößen und leitet die Skalierung ein.
  2. Der vm-monitor läuft in jeder VM. Er überwacht den Postgres-Speicher genau, validiert Anforderungen zur Downskalierung und passt die Größe des Caches an.
  3. Ein modifizierter Kubernetes-Scheduler behält den globalen Überblick über die verfügbaren Ressourcen. Jede Upskalierung muss vom Scheduler genehmigt werden, bevor Speicher zugewiesen wird.
  4. NeonVM wendet die Änderung an. Es handelt sich um eine benutzerdefinierte Kubernetes-Ressource und einen Controller, der mit QEMU und KVM erstellt wurde und CPU und Arbeitsspeicher einer laufenden VM hinzufügen oder entziehen kann. (Hinweis: Die Architektur von Lakebase Postgres hat ihren Ursprung in Neon, weshalb der Name der Ressource/des Controllers unverändert bleibt).
image3.png

Hochskalieren

Wie wir gerade gesehen haben, erfolgt das Hochskalieren, wenn eines der drei Ziele mehr Rechenleistung erfordert, als die VM derzeit hat. Eine Upskalierung folgt diesem Ablauf:

  1. Der autoscaler-agent berechnet das neue Ziel aus den CPU-, Speicher- und Arbeitssatz-Zielen.
  2. Der Kubernetes-Scheduler prüft, ob der Knoten die Anforderung erfüllen kann, ohne den Speicher zu überbelegen.
  3. Nach der Genehmigung aktualisiert der autoscaler-agent die NeonVM-Ressource.
  4. Der NeonVM-Controller fügt der laufenden VM CPU und Arbeitsspeicher hinzu.
  5. Der vm-monitor erweitert den Cache der Rechenressource, um die neue Kapazität zu nutzen.

Der Scheduler ist die einzige „Source of Truth“ (Informationsquelle) für die Zuweisung. Er sieht sowohl die normale Kubernetes-Planung als auch Anforderungen zur automatischen Skalierung. Ohne diese Koordination könnte der Scheduler eine neue Arbeitslast genau in dem Moment auf einem Knoten platzieren, in dem die automatische Skalierung den verbleibenden Speicher einer Postgres-VM zuweist.

Wenn ein Knoten zu voll ist, um direkt vor Ort zu wachsen, kann NeonVM die VM im laufenden Betrieb (Live-Migration) auf einen anderen Knoten verschieben. Die VM behält ihre IP-Adresse, sodass bestehende Verbindungen offen bleiben. Die Rechenressourcen von Lakebase Postgres müssen kaum dauerhaften lokalen Zustand verschieben, sodass die Migration hauptsächlich den VM-Speicher und den Laufzeitstatus betrifft.

Herunterskalieren

Das Herunterskalieren verwendet genau dieselben Komponenten, mit einer zusätzlichen Prüfung innerhalb der VM. Der vm-monitor bestätigt, dass nach dem Entfernen des Speichers immer noch genügend für Postgres und den Rest des Gasts übrig bleibt. Wenn dies nicht der Fall ist, wird das Herunterskalieren nicht durchgeführt.

Hinweis: Das Herunterskalieren ist genauso wichtig wie das Hochskalieren. Einige Systeme zur automatischen Skalierung fügen schnell Kapazität hinzu, geben sie aber nur langsam wieder frei, sodass Datenbanken noch lange nach dem Abklingen einer Spitze überdimensioniert bleiben. Lakebase Postgres behandelt beide Richtungen gleich. Das Ziel ist es, der Arbeitslast von Moment zu Moment so genau wie möglich zu folgen, damit Sie nicht mehr für Kapazität bezahlen, sobald Sie diese nicht mehr benötigen.

Fazit

Lakebase Postgres überwacht die Arbeitslast im laufenden Betrieb und passt die Rechenleistung in Echtzeit an. Die Lakebase-Architektur macht dies möglich: Da der Speicher entkoppelt und eigenständig dauerhaft ist, können sich die Rechenressourcen frei bewegen, ohne sich um die Daten sorgen zu müssen.

Das resultierende System skaliert in beide Richtungen auf einer aktiven Datenbank, ohne Verbindungen zu trennen. Vor allem blickt es über das offensichtliche Signal hinaus: Die alleinige Überwachung der CPU würde eine Arbeitslast übersehen, die aufgrund von Cache-Misses ins Stocken geraten ist. Daher verfolgt der Algorithmus auch den Speicherdruck und eine zeitabhängige Schätzung des Arbeitssatzes.

Die finale Schleife läuft auf drei Zeitskalen:

  • 100 Millisekunden: Der vm-monitor prüft den Postgres-Speicher, um schnelle Zuweisungen zu erfassen
  • 5 Sekunden: Der autoscaler-agent liest CPU und Gesamtspeicher aus
  • 20 Sekunden: Der autoscaler-agent wertet Schätzungen des Arbeitssatzes über Zeitfenster von einer bis 60 Minuten aus

So kann eine Produktionsdatenbank ihre Größe mehr als 32.000 Mal pro Monat ändern.

image7.png

Da Rechenleistung immer teurer und umkämpfter wird, ist das Bezahlen für eine selten erreichte Spitze ein Entwicklungsmuster, das bald nicht mehr tragbar sein könnte. Die automatische Skalierung bereitet Postgres auf Arbeitslasten vor, bei denen verschwendete Rechenleistung keine Option ist.

Jetzt ausführen

Bitten Sie Ihren Agenten, Lakebase Postgres bereitzustellen und das Autoscaling auf die Probe zu stellen. Jetzt loslegen.

Lakebase Postgres kann als eigenständige Datenbank verwendet werden, und Sie können sie auch in die restliche Databricks Data + AI Platform integrieren: Unity Catalog-Governance, Lakehouse-Analysen, Notebooks und KI-Workflows.

(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag

Erhalten Sie die neuesten Beiträge in Ihrem Posteingang

Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.