So macht man Postgres langsam
(byteofdev.com)- Vorstellung eines experimentellen Ansatzes zu Parameterkombinationen, die die Postgres-Performance extrem verschlechtern können
- Üblicherweise werden Cache, Indizes, WAL, I/O und verschiedene andere Faktoren in die entgegengesetzte Richtung getunt
- Durch extreme Manipulation von shared_buffers, autovacuum und WAL-bezogenen Optionen wurde ein Rückgang auf das 42.000-Fache erreicht
- Auch neue Funktionen wie io_method und io_workers aus den neuen Postgres-18/19-Versionen wurden genutzt, um die Begrenzung auf einen einzelnen I/O-Thread zu testen
- Die Versuchsergebnisse zeigen, dass allein über die Postgres-Konfigurationsdatei eine extreme Leistungsverschlechterung möglich ist
Überblick
Dieser Beitrag beschreibt ein Experiment, das im Gegensatz zum üblichen Postgres-Tuning, das auf Beschleunigung abzielt, ausschließlich darauf ausgerichtet ist, PostgreSQL langsamer zu machen, indem nur verschiedene Konfigurationswerte verändert werden, um die Performance bis an ihre Grenzen zu verschlechtern.
Der Test basiert auf der TPC-C-Workload von BenchBase (128 Lagerhäuser, 100 Verbindungen, jeweils Versuche mit bis zu 10.000 Transaktionen pro Sekunde, aktuelles Postgres 19devel, Ryzen 7950x, 32 GB RAM, 2 TB SSD, Laufzeit 120 Sekunden).
Mit den Standardwerten lag die Leistung bei 7082 TPS; anschließend wurde schrittweise beobachtet, wie stark sie durch die jeweiligen Parameteränderungen verlangsamt wird.
Caching drastisch reduzieren
- Postgres nutzt einen starken Cache (shared_buffers), um disk I/O zu reduzieren
- Wird shared_buffers vom Standardwert (10 GB) auf 8 MB reduziert, fällt die TPS auf etwa 1/7 (1052 TPS)
- Es wurde beobachtet, dass die Cache-Hit-Rate von 99,90 % auf 70,52 % sinkt und die read-
syscalls um mehr als das 300-Fache zunehmen - Es wurde versucht, auf 128 kB zu reduzieren, aber Postgres erlaubt mindestens nur etwa 2 MB, wodurch die Leistung weiter auf 485 TPS sinkt
Mehr Hintergrundarbeit erzeugen (autovacuum-Tuning)
- Alle Schwellwerte rund um autovacuum wurden auf das Minimum gesetzt, sodass bei fast jeder Operation ein Vacuum läuft
- Kombinationen wie
autovacuum_vacuum_insert_threshold=1,autovacuum_naptime=1usw. - Vacuum läuft dadurch praktisch fast jede Sekunde erneut, selbst wenn faktisch kaum Arbeit anfällt
- Kombinationen wie
- In diesem Zuge wurde maintenance_work_mem auf 128 kB reduziert und das komplette autovacuum-Logging aktiviert
- Das Ergebnis: Die TPS sinkt auf 293 (weniger als 1/20 des Ausgangswerts)
- Anhand der Echtzeit-Logs zu autovacuum wurde bestätigt, dass die häufige Hintergrundarbeit tatsächlich die Ursache des Performance-Einbruchs ist
WAL-Schreibvorgänge maximal verschlechtern
- Alle WAL-bezogenen Parameter wurden auf den schlechtestmöglichen Zustand eingestellt
wal_writer_flush_after=0,wal_writer_delay=1,wal_sync_method=open_datasyncusw.- Checkpoints werden alle 30 Sekunden erzwungen,
min/max_wal_size=32MBwird auf dem Minimum gehalten wal_level=logical,wal_log_hints=onusw., sodass sogar unnötige Informationen ins WAL geschrieben werden- Zusätzliche Lasten wie
track_wal_io_timing,summarize_walwurden ebenfalls aktiviert
- Dadurch sinkt die TPS auf 98 (weniger als 1/70 des Ausgangswerts)
- In den Logs zeigt sich anomales Verhalten, etwa dass Checkpoints alle paar hundert ms wiederholt auftreten
Wirkung von Indizes entfernen
- Die Nutzung von Indizes wurde dadurch praktisch deaktiviert, dass alle Werte, mit denen ihre Kosten berechnet werden, auf das Maximum gesetzt wurden (
random_page_cost=1e300,cpu_index_tuple_cost=1e300) shared_bufferswurde zur Stabilität wieder auf 8 MB erhöht, und die TPS fiel auf 0,87 (eine Verlangsamung um das 7000-Fache)
Einzelnen I/O-Thread erzwingen
- Nutzung neuer Funktionen aus Postgres 18+
- Mit
io_method=worker,io_workers=1wird sämtliches I/O auf einen einzelnen Worker-Thread beschränkt - Die TPS fällt weiter auf 0,016 (42.000-fach langsamer)
- Im Test mit 100 Verbindungen und 120 Sekunden wurden nur 11 Transaktionen erfolgreich abgeschlossen
Fazit und Hinweise zur Reproduktion
- Es wird gezeigt, dass sich eine Produktionsdatenbank mit insgesamt nur 32 Parameter-Manipulationen praktisch in einen Zustand der „Lähmung“ versetzen lässt
- Allein durch Änderungen in
postgresql.conflässt sich die Leistungsverschlechterung maximieren - Wer das Experiment reproduzieren möchte, sollte BenchBase Postgres, die oben genannte TPC-C-Umgebung und die vollständige Liste aller Einstellungen heranziehen
- Einige zusätzliche Parameter oder weitere Versuche zur Verlangsamung sind nicht enthalten
Zusammenfassung der Parameter
shared_buffers = 8MB- autovacuum-bezogene thresholds/scale_factor = auf 0–1 minimiert
- Vacuum-bezogene Kosten sowie Speicher/Logging: minimiert bzw. maximiert
- WAL-bezogene sync/flush/Logging/Level usw.: auf langsam gehalten
- Index-bezogene
random_page_cost,cpu_index_tuple_cost: auf1e300gesetzt io_method = worker,io_workers = 1- Weitere Detailwerte siehe Liste im Haupttext
Schluss
- Schon allein über die Datei
postgresql.conflässt sich ein massiver Performance-Einbruch auslösen - In der Praxis kann diese Kombination umgekehrt als Referenz für effiziente Performance-Optimierung dienen
- Der Beitrag endet mit dem Hinweis, dass der Autor das Experiment wegen Rückenschmerzen unterbrechen musste
2 Kommentare
Hacker-News-Kommentare
Großartig. Ich mag diesen Ansatz sehr.