PostgreSQL: Kein VACUUM mehr, kein Bloat mehr
(orioledata.com)- Die neue Storage-Engine OrioleDB für PostgreSQL beseitigt den ressourcenintensiven VACUUM-Prozess und löst das Problem des Table-Bloat
- Herkömmliches PostgreSQL benötigt aufgrund seiner MVCC-Architektur manuelles Vacuuming und Autovacuum; beide Verfahren verbrauchen erhebliche Systemressourcen
- OrioleDB verarbeitet Datenänderungen effizient mit Undo-Logs auf Zeilen- und Blockebene sowie automatischer Page-Zusammenführung und konsolidiert fragmentierte Daten
- In synthetischen Benchmarks wurden durch das Aktualisieren nur eines einzelnen Index, die automatische Zusammenführung dünn belegter Pages und WAL auf Zeilenebene 5-fach höhere TPS bei geringerem Ressourcenverbrauch erreicht
- Damit wird ein langjähriges Problem gelöst: VACUUM entfällt, der Wartungsaufwand sinkt und PostgreSQL bietet bessere Performance und User Experience
Geschichte und Grenzen von PostgreSQL VACUUM
- Der VACUUM-Prozess ist ein historisches Erbe aus dem Berkley-Postgres-Projekt und dessen Konzept des infinite time-travel, das später von der Community verworfen wurde
- Dennoch führte dies zur Implementierung eines MVCC (Multi-Version Concurrency Control)-Systems, das anfällig für Table-Bloat ist
- MVCC ist für die Verarbeitung gleichzeitiger Transaktionen vorteilhaft, bringt aber die Notwendigkeit von manuellem Vacuuming mit sich, um alte und unnötige Daten zu bereinigen
- Manuelles Vacuuming ist arbeitsintensiv und eine potenzielle Quelle von Systemineffizienz
- Um die Last manueller Arbeit zu verringern, wurde später Autovacuum eingeführt
- Das war ein großer Fortschritt, aber keine perfekte Lösung, denn auch die Automatisierung verbraucht weiterhin erhebliche Systemressourcen
- Dies wurde als einer der Gründe genannt, warum Uber von PostgreSQL zu MySQL wechselte, und tauchte auch in Richard Bransons zehn Kritikpunkten an PostgreSQL auf
- Mit der Einführung von Heap-Only Tuples (HOT)-Updates und Microvacuum wurde der Bedarf an vollständigem Table-Vacuum reduziert
- Trotzdem blieb VACUUM ressourcenintensiv, und Tabellen blieben anfällig für Bloat
- Dies wurde als der von OtterTune am meisten gehasste Teil von PostgreSQL bezeichnet
- Trotz dieser Grenzen setzen viele Organisationen und Entwickler weiterhin auf PostgreSQL, unter anderem wegen seiner Robustheit, Skalierbarkeit und starken Community
- OtterTune erkannte das Problem an und entschied sich dennoch, PostgreSQL weiter zu verwenden
Die Kernfunktionen von OrioleDB
- OrioleDB ist eine neue PostgreSQL-Engine, die mit dem Hauptziel entwickelt wurde, Tabellen vor Bloat zu schützen und die Notwendigkeit regelmäßiger Wartung wie VACUUM zu beseitigen
- Dies wird durch Undo-Logs auf Zeilen- und Blockebene sowie automatische Page-Zusammenführung umgesetzt
- Undo-Logs auf Zeilen- und Blockebene bieten eine feinere Kontrolle und verarbeiten Datenänderungen effizienter
- Die automatische Page-Zusammenführung konsolidiert fragmentierte Daten kontinuierlich im Hintergrund
- So funktionieren die einzelnen Techniken
- Undo-Logs auf Zeilenebene erlauben In-Place-Updates
- Undo-Logs auf Blockebene entfernen Tupel aus dem Primärspeicher, die zwar gelöscht wurden, aber für einige Transaktionen noch sichtbar sind, und schaffen so Platz für neue Tupel
- Die automatische Zusammenführung dünn belegter Pages schützt Tabellen und Indizes auch nach vielen Löschvorgängen vor Bloat
- Das Ergebnis: weniger manuelle Eingriffe, geringerer Ressourcenverbrauch und eine deutlich geringere Anfälligkeit für Table-Bloat
Benchmark
- Der synthetische Benchmark wurde mit einem Initialisierungsskript aufgebaut, das eine Tabelle und fünf Indizes erstellt
- Es wird eine
test-Tabelle mit dem Primärschlüsselidsowie den Spaltenvalue1~value4(float8) undts(timestamp) erstellt - Für
value1,value2,value3,value4undtswird jeweils ein Index angelegt
- Es wird eine
- Das pgbench-Skript ist als Upsert ausgelegt und führt bei Konflikten ein dünn verteiltes Update auf genau einem Index aus
- Es führt INSERTs mit zufälligen
id-Werten im Bereich von 1 bis 10.000.000 aus und aktualisiert bei Konflikten nurts - Dieses dünn verteilte Update verursacht bei normalen PostgreSQL-Heap-Tabellen Index-Bloat
- Es führt INSERTs mit zufälligen
- Diese Vorteile des OrioleDB-Designs zeigt der Benchmark
- Dank Undo-Logs und In-Place-Updates aktualisiert OrioleDB nur den einen Index, dessen Wert sich geändert hat, während die PostgreSQL-Heap-Engine durch die Aktualisierung eines einzelnen Index-Felds HOT unwirksam macht, sodass alle Indizes aktualisiert werden
- Die automatische Page-Zusammenführung schützt dünn belegte Indizes vor Bloat; dünn belegte Pages werden automatisch zusammengeführt
- WAL auf Zeilenebene benötigt deutlich weniger Speicherplatz als WAL auf Blockebene und senkt dadurch die IOPS beim Schreiben des WAL
- Die kumulierten Verbesserungen von OrioleDB zeigen sich in folgenden Werten
- 5-fach höhere TPS pro Transaktion
- 2,3-fach geringere CPU-Last pro Transaktion
- 22-fach geringere IOPS pro Transaktion
- Kein Table- oder Index-Bloat
Die Bedeutung von OrioleDB
- Mit der Einführung von OrioleDB tritt die PostgreSQL-Community in eine neue Ära ein, in der VACUUM der Vergangenheit angehört
- Damit wird eine Lösung für eines der ältesten Probleme von PostgreSQL präsentiert, die den Nutzern mehr Effizienz und weniger Wartungsaufwand bietet
1 Kommentare
Hacker-News-Kommentare
Ein paar Dinge geben mir trotzdem zu denken. Zeilenweise Verarbeitung erzeugt Probleme bei Write-Ordering und
fsync-Ordering, und Seiten lassen sich leichter anordnen als Zeilen mit beliebiger GrößePostgreSQL ist bei der Datensicherheit sehr, vielleicht sogar extrem konservativ, und erreicht das vor allem durch
fsynczum richtigen Zeitpunkt; die Auswirkungen ziehen sich durch den gesamten I/O-Stack bis hinunter zur SSD-Firmware und machen alles langsamerMVCC ist für gleichzeitigen Zugriff sehr gut, aber die Oriole-Dokumentation sagt nicht, unter welchen Nebenläufigkeitsbedingungen die Diagramme entstanden sind
Titel und Einleitung der Oriole-Dokumentation fokussieren sich auf die Lösung von VACUUM, aber es scheint nicht wirklich belegt zu sein, dass das in PostgreSQL sichtbare „Rechteckwellen“-Diagramm größtenteils tatsächlich durch VACUUM verursacht wird. Andere Benchmarks von Percona (https://www.percona.com/blog/evaluating-checkpointing-in-postgresql/) zeigen kein so deutliches Rechteckwellen-Muster
Die Autoren kennen diese Probleme sicher, daher wäre ein Überblick hilfreich, wie sie daran herangegangen sind
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
Gerade weil PostgreSQL bei der Datensicherheit konservativ ist, ist das erste Ziel, eine reine Extension zu werden. Um Teil von PostgreSQL zu werden, braucht es Bewährung über längere Zeit
Es stimmt, dass Informationen zur Nebenläufigkeit fehlten; im Blogpost wurden inzwischen VM-Typ und Nebenläufigkeitsangaben ergänzt
Das Rechteckwellen-Muster kommt tatsächlich von Checkpoints. Der Grund für die Verbesserung ist hier in Wirklichkeit nicht VACUUM, sondern die Methode, nur die betroffenen Indizes zu aktualisieren, sowie zeilenbasiertes WAL, das den gesamten I/O reduziert
Sieht beeindruckend aus, aber ich frage mich, wie man mit dem Release-Zyklus des Mutterprojekts Schritt halten will
Hier wurde ein großes Open-Source-Projekt geforkt und erheblich verändert, und wenn man nicht glaubt, dass diese Änderungen upstream übernommen werden, weiß ich nicht, ob das eine gute Idee ist
Es sollte klar sein, ob das ein Spielzeugprojekt zum Spaß ist oder ein ernsthaftes Projekt, das langfristig gepflegt werden soll
Wenn es ein ernsthaftes Projekt ist, sollte dargelegt werden, wie verhindert werden soll, dass es später zu weggeworfener Software wird, wie künftige Releases des ursprünglichen Projekts übernommen werden sollen oder ob es als vollständig separates Projekt weitergehen soll
Da es eine Extension ist, könnte es zwar Upstream-Änderungen aus PostgreSQL übernehmen, aber wenn das einfach wäre, wäre es wohl von Anfang an Teil des PostgreSQL-Projekts geworden — ganz leicht scheint es also nicht zu sein
„Stimmt. Aber der Weg ist noch lang. Im Moment ist OrioleDB eine Extension, die zusammen mit Patches für den PostgreSQL-Core ausgeliefert wird. Das mittelfristige Ziel ist, OrioleDB zu einer reinen Extension zu machen, und das langfristige Ziel ist, OrioleDB zu einem Teil des PostgreSQL-Core zu machen.“
Beim nächsten Mal wäre es vielleicht besser, nicht gleich von Anfang an so scharf einzusteigen
https://news.ycombinator.com/item?id=36742001
Schon ein Beispiel für eine Behebung zu sehen, hilft definitiv. Wenn ein Unternehmen die Ressourcen hat, einen Postgres-Fork zu pflegen, ist das gut; wenn nicht, muss man abwägen, ob die Hürden bei der Nutzung dieses Forks den Performance-Gewinn wert sind
Ich wünschte, diese Geschichten à la „Uber ist von Postgres zu MySQL gewechselt“ würden endlich aufhören. Uber ist von Postgres als relationaler Datenbank zu etwas gewechselt, das faktisch eine eigene nichtrelationale Datenbank ist, in der MySQL als verteilter Key-Value-Store verwendet wird; das ist also keine Situation, die sich für die meisten Postgres-Nutzer direkt übertragen lässt
Unabhängig davon wird ein solches MVCC-Design, bei dem alte Daten in Undo-Logs/-Segmente verschoben werden, auch in Oracle DB verwendet, daher ist die Funktionsweise an sich erprobt
Die gemeinsame Schwierigkeit ist, dass das Lesen alter Datenversionen langsamer wird. Man muss sie im Log suchen, und manchmal werden Daten aus dem Log entfernt, bevor eine Transaktion beendet ist, was zum berüchtigten Fehler Snapshot Too Old führen kann
Im Artikel habe ich nicht gesehen, wann eine Zeile aus dem Undo-Log entfernt wird. Wenn sie entfernt wird, sobald sie nicht mehr gebraucht wird, dürfte ein ähnlicher Umfang an Verwaltungsarbeit nötig sein; daher ist mir nicht klar, wo die Verbesserung herkommt. Und wenn es wie bei Oracle ein Ringpuffer ist, dem der Platz ausgehen kann, dann beginnen bei hoher Schreiblast lang laufende Transaktionen zu scheitern, was ziemlich unerquicklich ist
Je nachdem, was mit „Verwaltungsarbeit“ genau gemeint ist, fällt die Antwort unterschiedlich aus. Betrachtet man die Arbeitsmenge, dann gibt es eine Verbesserung, weil alte Undo-Records gesammelt und sehr günstig gelöscht werden können, etwa durch
unlinkvon Dateien. Ein VACUUM-Scan ist nicht nötigBetrachtet man die Speichernutzung, dann stimmt es, dass dieselbe Anzahl von Versionen denselben Speicherplatz belegt. Aber wenn alte Zeilenversionen in einem separaten Storage liegen, lässt sich die langfristige Degradation des Primär-Storage verhindern. OrioleDB implementiert außerdem automatisches Zusammenführen spärlicher Seiten
OrioleDB implementiert für das Undo-Log einen In-Memory-Ringpuffer. Wenn der Ringpuffer nicht alle Undo-Records aufnehmen kann, werden die ältesten Records in den Storage ausgelagert. Derzeit ist die Größe des Undo-Logs nicht begrenzt, und Records werden so lange aufbewahrt, wie irgendeine Transaktion sie benötigen könnte, daher gibt es keinen Fehler „Snapshot Too Old“
Es wäre allerdings denkbar, optional einen Oracle-artigen Fehler zu implementieren, damit sich die Undo-Größe begrenzen lässt. Es lohnt sich auch, die Architektur-Dokumentation auf GitHub anzusehen
https://github.com/orioledb/orioledb/blob/main/doc/arch.md
Natürlich vermeidet MySQL VACUUM, indem es bei der Nebenläufigkeit erhebliche Abstriche macht
Der Titel klang vielversprechend, aber mein erster Eindruck war ernüchternd. Das Haupt-README auf GitHub[1] wirkt wie Marketing-Sprech eines Unternehmens
Bisher habe ich gelernt, dass OrioleDB eine neue Storage-Engine für PostgreSQL ist, PostgreSQL die „meistgeliebte“ Datenbank sei, OrioleDB eine Erweiterung ist, die auf anderen Erweiterungen aufbaut, und OrioleDB die Tür zur Cloud öffnet
Nach den Betrügereien rund um Kryptowährungen und Web 3.0 hätte ich gedacht, dass man bei einem Projekt, das etwas so Wichtiges wie PostgreSQL erweitert und verbessert, bei der Veröffentlichung einen solchen Ansatz vermeidet
[1] https://github.com/orioledb/orioledb
Schwer vorstellbar, wie man das noch klarer hätte schreiben können. Die Table-Access-Method wurde in PostgreSQL eingeführt, um alternative Storage-Formen wie zheap oder spaltenorientierten Storage zu unterstützen
Es ist wichtig, das zu erwähnen. Es gibt etliche PostgreSQL-Forks, die alternative Datenspeichersysteme aufsetzen, aber OrioleDB ist so konzipiert, dass es als Erweiterung auf einem nicht geforkten PostgreSQL läuft. So weit ist es zwar noch nicht, aber das ist die Richtung
Wenn man mit PostgreSQL vertraut ist, wirkt das README ziemlich klar
Das Design von Oriole scheint transaktionsbewusste Indizes und das Entfernen einzelner Einträge zu erfordern, was zusätzliche Kosten mit sich bringt
Zum Beispiel scheint ein Äquivalent zu GiST für Raumindizes wegen der Eigenschaft, dass sich die Position jedes Indextupels nicht exakt bestimmen lässt, aufwendig in der Pflege zu sein, und ein Äquivalent zu GIN für Volltextsuche könnte wegen geringerer Komprimierbarkeit der Posting-Bäume sehr groß werden
Außerdem kann ich mir bei der Verwendung von Index-Organized Tables schwer vorstellen, wie ein Äquivalent zu BRIN implementiert werden soll. BRIN erlaubt es, große Bereiche einer physischen Tabelle schnell aus Query-Ergebnissen auszuschließen, wenn dort keine interessanten Daten liegen. Man könnte zwar nach Primärschlüsselbereichen partitionieren, aber die Wertdichte des Primärschlüssels kann je nach Zeit und Wertebereich stark variieren
Ich frage mich, wie diese komplexeren, aber sehr nützlichen Indexmethoden umgesetzt werden sollen
Es gibt auch Probleme, die auftreten können, wenn sich Sortierregeln, also Collations, ändern. Da der Heap von Postgres und VACUUM die Sortierreihenfolge nicht kennen, kann man Schäden nach einer Collation-Änderung oft beheben, indem man Zeilen, die nun an der falschen Stelle stehen, löscht und neu einfügt, worauf VACUUM die kaputten Tupel irgendwann aufräumt
Bei Oriole scheint das schwieriger zu sein, weil sich das ursprüngliche Tupel, das per Point Lookup entfernt werden müsste, nicht finden lässt, und zur Behebung bekannter Fälle von Indexkorruption dürfte möglicherweise ein kompletter Index-Neuaufbau nötig sein, was den Wartungsaufwand ziemlich hoch erscheinen lässt
Bei GIN-ähnlicher Funktionalität bleibt die Komprimierung der Posting-Listen weiterhin möglich. Eine mögliche Option ist, Undo-Records nicht mit einem einzelnen Eintrag der Posting-Liste zu verknüpfen, sondern mit der gesamten Posting-Liste
Für BRIN dürfte es kein direktes Äquivalent geben, da Index-Organized Tables verwendet werden. Allerdings kann man mit den Union Keys auf den internen Seiten des Primärschlüssels interessante Dinge tun
Das Problem mit Collations stimmt und ist schwerwiegend. Vor dem GA-Release müssen wahrscheinlich alle Collation-sensitiven Indizes auf eine bestimmte libicu-Collation-Version festgelegt werden
Die Argumentation des Artikels ist überzeugend, und auch die Benchmarks scheinen die Leistungsbehauptungen zu stützen, aber die Abgrenzung zwischen der vorgeschlagenen neuen Storage Engine, also OrioleDB, und PostgreSQL selbst ist für mich nicht ganz klar.
Abgesehen von kommerziellen Motiven und dem Wunsch, mit den im Artikel beschriebenen Innovationen Geld zu verdienen: Gibt es einen Grund, das als neue Datenbank namens OrioleDB zu vermarkten, statt diese Verbesserungen zum Upstream beizutragen?
Die Änderungen in OrioleDB sind jedoch zu groß, um sie schrittweise einzubringen. Deshalb vergleichen wir OrioleDB mit der aktuellen PostgreSQL-Engine, also nicht nur mit dem Heap, sondern auch mit mehreren darunterliegenden Subsystemen.
Details dazu finden sich insbesondere auf den Folien 9 bis 11 von https://www.socallinuxexpo.org/sites/default/files/presentations/solving-postgres-wicked-problems.pdf.
Falls es sich um eine Engine-Erweiterung handelt, würde mich interessieren, ob es Auswirkungen bei der gemeinsamen Nutzung mit anderen Erweiterungen gibt. timescaledb[0] arbeitet zum Beispiel auf darunterliegenden Tabellen.
Ich frage mich, welche Effekte sich in so einem Fall ergeben würden.
create table xyz(...) using orioledb;select create_hypertable(xyz, ts);[0] https://github.com/timescale/timescaledb
Hätte OrioleDB Interesse daran, ein stabiles On-Disk-Format zuzusagen, sodass zwischen größeren Postgres-Versionen kein Upgrade-Verfahren mehr nötig wäre? Das wirkt wie eine Gelegenheit, dieses Problem zu lösen.
Dinge wie das Hinzufügen neuer Typen und ihrer unterstützenden Funktionen müssen über irgendein Upgrade-Verfahren eingespielt werden. Es gibt auch andere Katalogänderungen, etwa wenn das Spaltenlayout von Katalogtabellen geändert wird; auch dann braucht man ein Verfahren, das die zwischen den Versionen gespeicherten Daten aktualisiert.
Ohne ein Upgrade-Verfahren kann man den Katalog nicht ändern. Deshalb sind bei PostgreSQL nur Minor-Version-Upgrades durch reinen Binäraustausch möglich und lassen sich bei Problemen sicher zurückrollen.
Wenn Upgrades nur auf Änderungen an internen APIs, Planner und Executor beschränkt wären, würde das die Entwicklung stark einschränken. Es scheint unwahrscheinlich, dass OrioleDB die Notwendigkeit dieses Upgrade-Verfahrens beseitigen kann.
Der Großteil der Arbeit bei Cluster-Upgrades besteht darin, Katalogtabellen neu zu schreiben. Außerdem ist pg_upgrade bei den meisten Workloads sehr schnell, daher ist für mich auch nicht klar, wo hier ein großer Gewinn entstehen würde.
Die Formulierung „2,3-fach geringerer CPU-Overhead pro Transaktion“ stößt mir etwas auf. Bei Postgres schwankt die CPU-Auslastung zwischen 5 % und 65 %, während Oriole konstant bei 90 % liegt
Vorhersehbarkeit ist gut, aber den niedrigen Bereich um 85 % anzuheben, wirkt doch ziemlich bedenklich
Die gute Nachricht ist, dass vertikales Skalieren mit einer stärkeren CPU bei Oriole mehr Performance bringen kann. Bei Postgres dürfte die Performance auf dieselbe Weise hingegen nicht weiter steigen
Aus Sicht eines Desktop-Betriebssystems könnte man die Leerlaufzeit eines Postgres-Servers anderweitig nutzen, aber auf Servern erledigt man normalerweise eine Aufgabe und möchte eine dafür optimierte Maschine
Wenn man den TPS-Wert senkt, würde die CPU proportional mit sinken, und hier soll wohl gezeigt werden, wie hoch das Ganze skalieren kann
Wenn man das System auf 60 % CPU begrenzt, können sich die Gesamtzahlen ändern, aber wenn der TPS bei gleicher Auslastung 1,8-fach ist, ist das trotzdem ein Sieg. Das wirkt weniger wie Marketingtrick als vielmehr wie eine ziemlich gute Kennzahl
Wenn eine teure Server-CPU pro Einheit X Dollar kostet, man aber nur 60 % davon nutzen kann und realistisch auch nur so viel nutzen wird, verbrennt man pro Einheit effektiv 0,4X Dollar
Wenn man die Workload vertikal so weit bringen kann, dass eine Maschine bis zu 90 % ausgelastet wird, ist es normalerweise leicht, QoS- und Isolationsverfahren anzuwenden, um eine niedrigere Sättigung bei proportionaler Performance zu halten. Umgekehrt gilt das nicht. Wenn man nur 60 % der Gesamtauslastung einer Maschine nutzen kann und dann ausskalieren muss, ist ein Redesign nötig, um über 90 % zu kommen, und genau dieses Redesign ist hier passiert
Als kumuliertes Ergebnis der Verbesserungen bietet OrioleDB laut eigener Aussage 5-fach höheren TPS, 2,3-fach geringere CPU-Last pro Transaktion, 22-fach geringere IOPS pro Transaktion und kein Aufblähen von Tabellen und Indizes
Dass die CPU-Last schwankt, bedeutet nicht, dass Postgres „skaliert“, sondern dass es regelmäßig auf Performance-Bottlenecks stößt. Vermutlich wegen der nötigen VACUUM-Läufe, und das ist sehr I/O-empfindlich
Daher verwendet Postgres I/O nicht für die Verarbeitung von Queries, sondern für Aufräumarbeiten, und TPS sowie CPU-Auslastung brechen gemeinsam ein
Oriole hingegen bewältigt einen viel höheren Durchsatz deutlich konsistenter. Was würdest du bevorzugen: ein Auto, das beim Durchtreten des Gaspedals konstant 100 mph fährt, oder eines, das trotz durchgedrücktem Pedal heftig zwischen 40 und 70 mph schwankt?
Im Artikel gibt es einen Link mit dem recht interessanten Titel „10 Dinge, die Richard Branson an PostgreSQL nicht mag“. Es stellte sich heraus, dass der Verfasser dieses Blogposts nicht Richard, sondern Rick Branson war
Ach so, nicht derjenige