Entschlüsselung des Vortrags von 2015 von Илья Космодемьянский "Linux-Optimierung zur Verbesserung der PostgreSQL-Leistung"
Haftungsausschluss: Ich möchte darauf hinweisen, dass dieser Vortrag aus November 2015 stammt – mehr als 4 Jahre sind vergangen und es hat sich viel getan. Die im Vortrag behandelte Version 9.4 wird nicht mehr unterstützt. In den letzten 4 Jahren wurden 5 neue PostgreSQL-Versionen und 15 Kernel-Versionen von Linux veröffentlicht. Wenn man diese Stellen überarbeiten würde, würde sich letztendlich ein anderer Vortrag ergeben. Aber hier wird die fundamentale Linux-Optimierung für PostgreSQL behandelt, die auch heute noch relevant ist.


Mein Name ist Илья Космодемьянский. Ich arbeite bei PostgreSQL-Consulting. Ich werde jetzt ein wenig darüber sprechen, was man mit Linux in Bezug auf Datenbanken im Allgemeinen und PostgreSQL im Besonderen tun kann, denn die Prinzipien sind ziemlich ähnlich.
Worüber wird gesprochen? Wenn Sie mit PostgreSQL arbeiten, müssen Sie bis zu einem gewissen Grad ein UNIX-Administrator sein. Was bedeutet das? Wenn wir Oracle und PostgreSQL vergleichen, muss man bei Oracle zu 80 % ein DBA-Datenbankadministrator und zu 20 % ein Linux-Administrator sein.
Mit PostgreSQL wird es etwas komplizierter. Man muss viel besser verstehen, wie Linux funktioniert. Gleichzeitig sollte man den Entwicklungen hinterherlaufen, denn in letzter Zeit werden viele Updates veröffentlicht. Neue Kernel erscheinen, neue Funktionen werden hinzugefügt, die Performance wird verbessert usw.
Warum sprechen wir über Linux? Nicht nur, weil wir auf der Linux-Konferenz in St. Petersburg sind, sondern weil unter den modernen Bedingungen eines der sinnvollsten Betriebssysteme zur Nutzung mit Datenbanken überhaupt – und insbesondere mit PostgreSQL – Linux ist. Denn FreeBSD entwickelt sich leider in eine sehr merkwürdige Richtung. Es werden sowohl Leistungsprobleme als auch viele andere Herausforderungen auftreten. Die Performance von PostgreSQL unter Windows ist ein völlig eigenes, ernstes Thema, das darin besteht, dass Windows keinen gemeinsamen Speicher wie UNIX hat, und PostgreSQL darauf angewiesen ist, da es sich um ein multi-prozessbasiertes System handelt.
Exotika wie Solaris interessiert, denke ich, die wenigsten, also lass uns weitermachen.

Moderne Linux-Distributionen bieten über 1.000 Syctl-Parameter, je nachdem, wie der Kernel erstellt wird. Darüber hinaus gibt es zahlreiche Einstellmöglichkeiten, wenn wir uns auch die verschiedenen Schrauben anschauen. Es gibt Parameter für Dateisysteme, wie diese gemountet werden. Bei Fragen zur Inbetriebnahme: Was im BIOS aktiviert werden muss, wie die Hardware konfiguriert wird usw.
Das ist ein sehr umfangreiches Thema, über das man mehrere Tage sprechen könnte, nicht nur in einem kurzen Vortrag. Ich werde mich jetzt jedoch auf wichtige Punkte konzentrieren, wie man die Fallstricke vermeidet, die garantiert verhindern, dass Sie Ihre Datenbank unter Linux gut betreiben können, wenn Sie diese nicht beheben. Ein wichtiger Punkt ist, dass viele Parameter standardmäßig nicht auf die richtigen Einstellungen für Datenbanken gesetzt sind. Das bedeutet, dass es standardmäßig schlecht funktionieren oder gar nicht funktionieren wird.

Welche traditionellen Tuning-Ziele gibt es in Linux? Ich denke, dass es, da Sie alle mit der Verwaltung von Linux zu tun haben, nicht notwendig ist, besonders zu erklären, was Ziele sind.
Man kann folgende Komponenten tunen:
- CPU.
- Speicher.
- Speicherplatz.
- Sonstiges. Dies werden wir am Ende als Schlussfolgerung besprechen. Selbst Faktoren wie die Energieeffizienzpolitik können die Leistung auf sehr unvorhersehbare und unangenehme Weise beeinflussen.

Was sind die spezifischen Merkmale von PostgreSQL und Datenbanken im Allgemeinen? Das Problem ist, dass man nicht einfach an irgendeiner Schraube drehen kann und erwarten, dass sich die Leistung stark verbessert.
Ja, solche Schrauben gibt es, aber eine Datenbank ist ein komplexes Gebilde. Sie interagiert mit allen Ressourcen des Servers und bevorzugt eine vollständige Interaktion. Wenn Sie sich die aktuellen Empfehlungen von Oracle zur Nutzung des Host-Betriebssystems anschauen, werden Sie feststellen, dass es wie in dem Witz über den mongolischen Kosmonauten ist – füttern Sie den Hund und lassen Sie alles wie es ist. Geben wir der Datenbank alle Ressourcen, die Datenbank wird alles selbst regeln.
Im Prinzip ist die Situation bei PostgreSQL ähnlich. Der Unterschied besteht darin, dass die Datenbank nicht alle Ressourcen selbst abrufen kann; das heißt, an einigen Stellen muss man das auf Linux-Ebene selbst organisieren.
Die Hauptidee besteht nicht darin, einen bestimmten Zielwert auszuwählen und diesen zu optimieren, wie zum Beispiel den Speicher oder die CPU, sondern darin, die Workload zu analysieren und die Durchsatzkapazität so weit wie möglich zu verbessern. Damit die Daten, die unsere talentierten Programmierer erstellt haben, einschließlich unserer Nutzer, maximal effizient durch unsere Datenbank fließen können.

Hier ist eine Grafik zur Erklärung dessen, was wir meinen. Es gibt den Puffer des Linux-Betriebssystems, geteilten Speicher und die geteilten Puffer von PostgreSQL. Im Gegensatz zu Oracle arbeitet PostgreSQL direkt über den Kernel-Puffer. Das bedeutet, dass eine Seite von der Festplatte in den Shared Memory gelangen muss und dabei den Kernel-Puffer passieren muss – genau dasselbe gilt für die Rückführung.
Unter diesem System sind die Festplatten angesiedelt. Ich habe sie als Festplatten dargestellt. In Wirklichkeit können dort jedoch RAID-Controller und ähnliche Komponenten vorhanden sein.
Der Ein- und Ausgabeverkehr erfolgt in jedem Fall über diese Komponente.
PostgreSQL ist eine klassische Datenbank. Sie basiert auf Seiten. Alle Ein- und Ausgaben erfolgen über Seiten. Wir laden die Seiten in den Speicher. Wenn nichts passiert ist und wir sie nur gelesen haben, sinken sie schrittweise aus diesem Cache, aus den Shared Buffern, zurück auf die Festplatte.
Wenn wir irgendwo etwas ersetzt haben, wird die gesamte Seite als "schmutzig" markiert. Ich habe sie hier blau markiert. Das bedeutet, dass diese Seite mit dem Blockspeicher synchronisiert werden muss. Das heißt, als wir sie schmutzig gemacht haben, haben wir einen Eintrag im WAL erstellt. Und zu einem bestimmten Zeitpunkt trat das Phänomen namens Checkpoint auf. In dieses Protokoll wurde die Information geschrieben, dass er gekommen ist. Das bedeutet, dass alle schmutzigen Seiten, die zu diesem Zeitpunkt in den Shared Buffern vorhanden waren, mit der Festplatte des Speichers über fsync durch den Kernel-Puffer synchronisiert wurden.
Warum wird das gemacht? Wenn wir keinen Strom haben, wollen wir nicht in der Situation sein, dass alle Daten verloren gehen. Der persistenten Speicher, von dem uns alle erzählt haben, ist bisher nur eine theoretische Datenbank – das ist die vielversprechende Zukunft, auf die wir sicherlich hinarbeiten und die uns gefällt, aber derzeit leben wir noch in einem Rückstand von 20 Jahren. Natürlich muss all dies überwacht werden.
Das Ziel, die Bandbreite zu maximieren, besteht darin, an allen diesen Punkten Feinabstimmungen vorzunehmen, damit alles schnell hin und her läuft. Der Shared Memory ist hauptsächlich ein Seiten-Cache. In PostgreSQL haben wir eine Select-Anfrage gesendet, die Daten von der Festplatte abgerufen hat. Diese Daten haben die Shared Buffers erreicht. Um dies effizienter zu gestalten, benötigt man viel Arbeitsspeicher.
Damit alles gut und schnell funktioniert, müssen Sie das Betriebssystem auf allen Ebenen richtig konfigurieren. Außerdem sollten Sie die Hardware ausgewogen auswählen, denn wenn es an irgendeiner Stelle ein Ungleichgewicht gibt, können Sie sehr viel Speicher schaffen, aber dieser wird mit unzureichender Geschwindigkeit betrieben.
Lassen Sie uns jeden dieser Punkte durchgehen.

Um diese Seiten schneller hin und her zu bewegen, müssen folgende Punkte berücksichtigt werden:
- Zunächst muss effizienter mit dem Speicher gearbeitet werden.
- Zweitens, der Übergang, wenn die Seiten aus dem Speicher auf die Festplatte gelangen, sollte effizienter sein.
- Und drittens, es sollten hochwertige Festplatten vorhanden sein.
Wenn Sie 512 GB RAM in Server und alles am Ende auf eine SATA-Festplatte ohne jeglichen Cache ankommt, dann verwandelt sich der gesamte Datenbankserver nicht nur in eine Kürbis, sondern in einen Kürbis mit SATA-Schnittstelle. Sie werden direkt an Ihre Grenzen stoßen. Und nichts wird Sie retten.

Was den ersten Punkt zum Thema Speicher betrifft, so gibt es drei Dinge, die das Leben erheblich erschweren können.
Das erste ist NUMA. NUMA ist eine Technologie, die entwickelt wurde, um die Leistung zu verbessern. Je nach Arbeitslast können verschiedene Dinge optimiert werden. In seiner aktuellen Form ist es jedoch nicht besonders gut für Anwendungen wie Datenbanken geeignet, die intensiv den Page Cache und Shared Buffers nutzen.

In kurzen Worten. Wie erkennt man, dass mit NUMA etwas nicht stimmt? Es gibt ein unangenehmes Geräusch, plötzlich wird ein CPU überlastet. Dabei analysieren Sie die Anfragen in PostgreSQL und sehen, dass dort nichts dergleichen zu finden ist. Diese Abfragen sollten den CPU nicht so intensiv beanspruchen. Es kann lange dauern, dies zu bemerken. Es ist einfacher, von Anfang an den richtigen Ratschlag zu nutzen, wie man NUMA für PostgreSQL konfiguriert.

Was passiert tatsächlich? NUMA bedeutet Non-Uniform Memory Access. Worauf kommt es an? Sie haben einen CPU, neben dem befindet sich sein lokaler Speicher. Und dieser Speicher kann über Interconnects auf den Speicher anderer CPUs zugreifen.
Wenn Sie numactl --hardware, ausführen, erhalten Sie eine große Übersicht. Unter anderem gibt es ein Feld für Distanzen. Dort werden Zahlen stehen – 10-20, etwas in dieser Art. Diese Zahlen sind nichts anderes als die Anzahl der Hops, um diesen entfernten Speicher anzubinden und lokal zu nutzen. Im Grunde ist das eine gute Idee. Es verbessert die Leistung bei einer Reihe von Lasten erheblich.
Stellen Sie sich vor, ein CPU versucht zunächst, seinen lokalen Speicher zu nutzen, und greift dann über das Interconnect auf einen anderen Speicher zu. Und auf diesen CPU gelangt der gesamte Page-Cache von PostgreSQL – mehrere Gigabyte. In der Regel haben Sie immer den schlechtesten Fall, denn der CPU hat normalerweise wenig direkten Zugriff auf diesen Speichermodul. Der gesamte Speicher, der verwaltet wird, läuft über diese Interconnects. Das führt zu langsamen und unbefriedigenden Ergebnissen. Ihr Prozessor, der diesen Knoten betreut, ist ständig überlastet. Die Zugriffszeit auf diesen Speicher ist schlecht und langsam. Das ist die Situation, die Sie vermeiden möchten, wenn Sie dies für Datenbanken verwenden.
Daher ist es besser, wenn das Betriebssystem Linux gar nicht weiß, was dort vor sich geht. Es sollte den Speicher so ansprechen, wie es üblich ist.
Warum ist das so? Es scheint, als sollte es anders sein. Der Grund ist einfach: Wir benötigen viel Speicher für den Page-Cache – Dutzende, Hundert Gigabyte.
Wenn wir also all dies выделили und unsere Daten dort zwischengespeichert haben, wird der Nutzen der Nutzung des Caches deutlich größer sein als der Vorteil einer so cleveren Speicheranprache. Dadurch werden wir im Vergleich dazu erheblich profitieren, dass wir den Speicher mit NUMA effektiver ansprechen.
Deshalb gibt es im Moment zwei Ansätze, während wir auf eine bessere Zukunft warten, in der die Datenbank selbst erkennen kann, auf welchen CPUs sie läuft und woher sie etwas abrufen muss.

Der korrekte Ansatz besteht also darin, NUMA insgesamt zu deaktivieren., beispielsweise beim Neustart. In den meisten Fällen sind die Vorteile so erheblich, dass die Frage, wie es am besten gemacht wird, gar nicht aufkommt.
Es gibt eine andere Option. Wir nutzen sie häufiger als die erste, weil es für unsere Kunden, die Unterstützung benötigen, ein großes Problem darstellt, den Server neu zu starten. Ihr Geschäft hängt davon ab. Sie haben da Schwierigkeiten mit NUMA. Daher versuchen wir, weniger invasive Methoden zu verwenden, um den Dienst zu beenden, als einen Reboot durchzuführen, aber dabei muss man vorsichtig überprüfen, ob er tatsächlich beendet wurde. Denn wie die Erfahrung zeigt, es ist zwar gut, den übergeordneten Prozess PostgreSQL NUMA zu stoppen, jedoch ist es keineswegs garantiert, dass dies funktioniert. Man muss überprüfen und sicherstellen, dass es tatsächlich gestoppt wurde.
Es gibt einen informativen Beitrag von Robert Haas. Er ist einer der Committer von PostgreSQL und ein Schlüsselentwickler für alle grundlegenden Aspekte. Wenn man den Links in diesem Beitrag folgt, findet man einige interessante Geschichten darüber, wie NUMA den Menschen das Leben erschwert hat. Schauen Sie sich die Checkliste für Systemadministratoren an, um die notwendigen Einstellungen auf dem Server vorzunehmen, damit unsere Datenbank gut funktioniert. Diese Einstellungen sollten dokumentiert und überprüft werden, denn andernfalls könnte es problematisch werden.
Ich möchte darauf hinweisen, dass dies alle Einstellungen betrifft, über die ich sprechen werde. In der Regel werden Datenbanken im Master-Slave-Modus zur Ausfallsicherheit konfiguriert. Vergessen Sie nicht, diese Einstellungen auch auf dem Slave vorzunehmen, denn irgendwann werden Sie mit einem Ausfall konfrontiert werden, und dann wechseln Sie zum Slave, der zum Master wird.
In einer Notfallsituation, in der alles schiefgeht, klingelt ständig das Telefon, und der Chef kommt mit einem großen Stock, bleibt Ihnen keine Zeit, um die Situation zu überprüfen. Die Ergebnisse können dann äußerst bedauerlich sein.

Der nächste Punkt sind die Huge Pages. Huge Pages sind schwer isoliert zu testen, und wirklich sinnvoll ist es auch nicht, obwohl es Benchmarks gibt, die das können. Diese lassen sich leicht googeln.
Worin besteht der Sinn? Sie haben einen nicht besonders teuren Server mit viel RAM, zum Beispiel mehr als 30 GB. Sie verwenden keine Huge Pages. Das bedeutet, dass Sie unweigerlich einen Overhead bei der Nutzung des Speichers haben, und dieser Overhead ist alles andere als angenehm.

Warum ist das so? Was passiert hier? Das Betriebssystem weist den Speicher in kleinen Blöcken zu. So praktisch, so hat sich das historisch entwickelt. Und wenn man ins Detail geht, muss das OS virtuelle Adressen in physische umwandeln. Dieser Prozess ist nicht ganz einfach, weshalb das OS das Ergebnis dieser Operation im Translation Lookaside Buffer (TLB) zwischenspeichert.
Da der TLB ein Cache ist, treten dabei die typischen Cache-Probleme auf. Erstens: Wenn Sie sehr viel Arbeitsspeicher haben und dieser in kleinen Blöcken zugewiesen wird, wird dieser Buffer sehr groß. Und je größer der Cache ist, desto langsamer wird die Suche darin. Der Overhead ist erheblich, und er verbraucht Speicherplatz, was bedeutet, dass der Arbeitsspeicher für etwas Unnötiges verwendet wird. Das ist Punkt eins.
Zweitens: Je größer der Cache in dieser Situation wird, desto höher ist die Wahrscheinlichkeit für Cache-Misses. Die Effizienz dieses Caches sinkt rapide mit zunehmender Größe. Daher haben die Betriebssysteme einen einfachen Ansatz entwickelt. In Linux wird dieser bereits seit langem verwendet. In FreeBSD ist er erst kürzlich eingeführt worden. Aber wir sprechen hier über Linux. Dies sind die Huge Pages.
Es ist wichtig zu betonen, dass die Idee der Huge Pages ursprünglich von Gemeinschaften wie Oracle und IBM vorangetrieben wurde, das heißt, dass Datenbankhersteller fest davon überzeugt waren, dass dies auch für Datenbanken nützlich ist.

Und wie bringt man das mit PostgreSQL zusammen? Zunächst müssen Huge Pages im Linux-Kernel aktiviert sein.
Zweitens müssen sie explizit mit dem sysctl-Parameter angegeben werden – wie viele es sind. Die Zahlen stammen von einem älteren Server. Sie können berechnen, wie viele Shared Buffers Sie ungefähr haben, damit die Huge Pages dort hinein passen.
Wenn der gesamte Server PostgreSQL zugewiesen ist, ist ein guter Ausgangspunkt, entweder 25 % des Arbeitsspeichers für die Shared Buffers zu reservieren oder 75 %, wenn Sie sicher sind, dass Ihre Datenbank problemlos in diese 75 % passt. Dies ist der erste Ausgangspunkt. Berechnen Sie, wenn Sie 256 GB RAM haben, dass Sie entsprechend 64 GB für die Shared Buffers verwenden sollten. Schätzen Sie etwas großzügig – was diese Zahl sein sollte.
Bis zur Version 9.2 (wenn ich mich nicht irre, ab Version 8.2) konnte man PostgreSQL mit Huge Pages über eine Drittanbieter-Bibliothek integrieren. Das sollte immer gemacht werden. Erstens muss der Kernel in der Lage sein, Huge Pages korrekt zuzuweisen. Und zweitens muss die Anwendung, die damit arbeitet, sie auch nutzen können. Einfach so kann sie das nicht. Da PostgreSQL Speicher im System 5-Stil zugewiesen hat, konnte dies mit libhugetlbfs - das ist der vollständige Name der Bibliothek - realisiert werden.
In Version 9.3 wurde die Leistung von PostgreSQL bei der Speicherverwaltung verbessert und die System 5-Methode zur Speichereinteilung wurde verworfen. Alle waren sehr erfreut, denn sonst versucht man, zwei PostgreSQL-Instanzen auf einem Rechner zu starten, und es sagt, dass nicht genug Shared Memory vorhanden ist. Und es verlangt, dass man sysctl anpassen muss. Und der sysctl ist so beschaffen, dass man sich auch neu starten muss, usw. Insgesamt waren alle erleichtert. Aber die Speicherzuweisung über mmap hat die Verwendung von Huge Pages gestört. Die meisten unserer Kunden nutzen große Shared Buffers. Daher haben wir dringend empfohlen, nicht auf 9.3 umzusteigen, da der Overhead dort in ansehnlichen Prozentwerten zu zunehmen begann.
Die Community hat jedoch auf dieses Problem reagiert und in Version 9.4 wurde diese Funktionalität erheblich überarbeitet. In der Version 9.4 gibt es nun einen Parameter in postgresql.conf, mit dem Sie den try-Status auf on oder off setzen können.
Try ist der sicherste Parameter. Beim Start von PostgreSQL, wenn der Shared Memory zugewiesen wird, versucht das System, den Speicher aus den Huge Pages zu verwenden. Wenn dies nicht gelingt, fällt es auf die normale Zuweisung zurück. Wenn Sie FreeBSD oder Solaris verwenden, können Sie try einstellen; das ist immer sicher.
Wenn der Parameter auf on gesetzt ist, startet das System einfach nicht, wenn es nicht in der Lage ist, Speicher aus den Huge Pages zuzuweisen. Hier ist es eine Frage der individuellen Präferenz. Wenn Sie jedoch try benutzen, überprüfen Sie, ob tatsächlich der benötigte Speicher zugewiesen wurde, da es viele Möglichkeiten für Fehler gibt. Momentan funktioniert diese Funktionalität nur auf Linux.
Eine kleine Anmerkung, bevor wir weitermachen: Transparent Huge Pages sind für PostgreSQL bisher nicht geeignet. Er kann sie nicht richtig nutzen. Bei Transparent Huge Pages profitieren Sie nur bei extrem großen Arbeitsspeichern, wenn ein großer Teil des gemeinsamen Speichers benötigt wird. Wenn Sie Terabytes an RAM haben, könnte das eine Rolle spielen. Bei alltäglichen Anwendungen mit 32, 64, 128 oder 256 GB RAM auf der Maschine ist es besser, die normalen Huge Pages zu verwenden und die Transparenten einfach auszuschalten.

Der letzte Punkt zur Speicherverwaltung ist nicht direkt mit dem Durchsatz verbunden, kann aber das Leben stark erschweren. Die gesamte Bandbreite leidet erheblich darunter, dass der Server ständig swappt.
Und das wird in mehreren Momenten sehr unangenehm sein. Das Hauptproblem besteht darin, dass sich das Verhalten der modernen Kernel geringfügig von älteren Linux-Kernel unterscheidet. Das ist etwas, worauf man nicht gerne tritt, denn wenn wir über die Arbeit mit Swap sprechen, endet das nicht mit einem rechtzeitigen Eingreifen des OOM-Killers. Und ein OOM-Killer, der nicht rechtzeitig kommt und PostgreSQL abschaltet, ist unangenehm. Das erfahren alle, das heißt, bis zum letzten Benutzer.

Was passiert? Sie haben eine große Menge RAM, alles funktioniert gut. Aber aus irgendeinem Grund hängt der Server im Swap und verzögert sich dadurch. Es scheint viel Speicher vorhanden zu sein, aber so ist es eben.

Früher haben wir empfohlen, vm.swappiness auf null zu setzen, das heißt, Swap zu deaktivieren. Früher schien es, dass 32 GB RAM und die entsprechenden Shared Buffers eine enorme Menge sind. Der Hauptzweck von Swap besteht darin, einen Platz zu haben, um Inhalte auszuschalten, wenn wir ausfallen. Und das wurde nicht mehr wirklich erfüllt. Und was macht man dann mit diesen Inhalten? Das ist eine Aufgabe, bei der es nicht wirklich klar ist, warum Swap benötigt wird, insbesondere in dieser Größe.
In den neueren, also den dritten Kernel-Versionen, hat sich das Verhalten geändert. Wenn Sie den Swap auf null setzen, also deaktivieren, wird der OOM-Killer früher oder später selbst bei noch vorhandenem Arbeitsspeicher aktiviert, um die Prozesse mit dem höchsten Ressourcenverbrauch zu beenden. Er geht davon aus, dass bei dieser Arbeitslast nur noch wenig verfügbar ist und dass wir ausfallen könnten, d.h. er wird nicht systemwichtige Prozesse beenden, sondern etwas weniger Wichtiges. Dabei handelt es sich häufig um einen intensiven Verbraucher des Shared Memory, konkret um den Postmaster. Nach diesem Eingriff kann man froh sein, wenn die Datenbank nicht wiederhergestellt werden muss.
Deshalb ist es meines Wissens nach momentan standardmäßig so, dass die meisten Distributionen bei etwa 6 liegen, also, ab wann man beginnen sollte, Swap zu verwenden, je nachdem, wie viel Arbeitsspeicher noch verfügbar ist. Wir empfehlen jetzt, vm.swappiness = 1 einzustellen, da dies quasi die Nutzung von Swap deaktiviert, jedoch nicht die unangenehmen Effekte mit einem unerwartet auftretenden OOM-Killer bringt, die dann alles mit sich reißen.

Was kommt als Nächstes? Wenn wir über die Leistung von Datenbanken sprechen und uns allmählich den Datenträgern nähern, greifen alle sich an den Kopf. Denn die Wahrheit, dass Festplatten langsam und der Arbeitsspeicher schnell ist, ist jedem seit der Kindheit bekannt. Und jeder weiß, dass es in Datenbanken Probleme mit der Festplattengeschwindigkeit geben wird.
Das Hauptproblem mit der PostgreSQL-Leistung, das mit Checkpoint-Spitzen zusammenhängt, resultiert nicht daraus, dass die Festplatte langsam ist. Es liegt vielmehr daran, dass die Bandbreite von Arbeitsspeicher und Festplatte nicht ausgewogen ist. Diese Unausgewogenheit kann an verschiedenen Stellen auftreten. PostgreSQL ist nicht richtig konfiguriert, das Betriebssystem ist nicht optimiert, die Hardware ist ungeeignet oder nicht richtig eingestellt. Dieses Problem tritt nur dann nicht auf, wenn alles richtig läuft, d.h. entweder keinerlei Last vorhanden ist oder die Konfiguration und Hardware gut ausgewählt sind.

Was ist das und wie sieht es aus? Normalerweise sind es Menschen, die mit PostgreSQL arbeiten und öfter mit diesem Thema in Berührung kommen. Ich werde das erklären. Wie bereits erwähnt, führt PostgreSQL regelmäßig Checkpoints durch, um die schmutzigen Seiten im Shared Memory auf die Festplatte zu sichern. Wenn wir einen großen Umfang an Shared Memory haben, wirkt sich der Checkpoint intensiv auf die Festplatte aus, da er diese Seiten mit fsync sichert. Diese gelangen in den Kernel-Puffer und werden über fsync auf die Festplatten geschrieben. Und wenn der Umfang groß ist, können wir einen unerfreulichen Effekt beobachten, nämlich eine sehr hohe Auslastung der Festplatten.
Hier habe ich zwei Bilder. Ich werde jetzt erklären, was das ist. Es handelt sich um zwei zeitlich korrelierte Grafiken. Die erste Grafik zeigt die Festplattenschutz. Hier erreicht sie in diesem Moment fast 90 %. Wenn Ihre Datenbank mit physischen Festplatten und einem RAID-Controller eine Auslastung von fast 90 % hat, dann sind das schlechte Nachrichten. Das bedeutet, dass es nicht mehr lange dauern wird, bis es 100 % erreicht und der Ein- und Ausgabeprozess stoppt.
Wenn Sie ein Festplattenspeichersystem haben, ist die Geschichte ein wenig anders. Es hängt davon ab, wie es konfiguriert ist, um welchen Typ von Array es sich handelt, usw.
Parallel dazu wurde hier ein Zeitplan aus einer internen Postgres-Ansicht konfiguriert, die beschreibt, wie der Checkpoint erfolgt. In Grün wird angezeigt, wie viele Buffer, also diese "schmutzigen" Seiten, zu diesem Zeitpunkt in diesem Checkpoint zur Synchronisierung angekommen sind. Das ist das Wichtigste, was Sie hier wissen müssen. Wir sehen, dass hier viele Seiten angekommen sind und irgendwann gestoßen sind, d.h. wir haben ununterbrochen geschrieben, und es ist offensichtlich, dass das Festplattensystem hier stark ausgelastet ist. Der Checkpoint hat erheblichen Einfluss auf die Disk-Performance. Ideal sollte die Situation eher so aussehen, dass wir weniger Schreibvorgänge hatten. Mit den richtigen Einstellungen können wir dies beheben, um sicherzustellen, dass es zukünftig so bleibt. Das heißt, die Auslastung ist gering, aber irgendwo schreiben wir dennoch etwas.
Was können Sie tun, um dieses Problem zu lösen? Wenn Ihr IO unter der Datenbank steht, bedeutet das, dass alle Benutzer, die ihre Anfragen ausführen möchten, warten müssen.

Betrachtet man es aus der Perspektive von Linux, wenn Sie gute Hardware verwenden, sie richtig konfigurieren und PostgreSQL so einstellen, dass es die Checkpoints seltener erstellt, diese über die Zeit verteilt, dann landen Sie bei den Standardparametern von Debian. Für die meisten Linux-Distributionen sieht das folgendermaßen aus: vm.dirty_ratio=20, vm.dirty_background_ratio=10.
Was bedeutet das? Mit dem Kernel 2.6 wurde ein Daemon für das Flushing eingeführt. Pdglush, abhängig davon, wer es nutzt, der sich um das Hintergrund-Entleeren von schmutzigen Seiten aus dem Kernel-Puffer kümmert und das Entleeren erzwingt, wenn es unbedingt notwendig ist, um schmutzige Seiten zu entleeren, wenn das Hintergrund-Entleeren nicht mehr hilft.
Wann tritt der Hintergrund ein? Wenn 10 % des gesamten Arbeitsspeichers, der auf dem Server vorhanden ist, mit schmutzigen Seiten im Kernel-Puffer belegt sind, wird eine spezielle Funktion zum Hintergrundschreiben aufgerufen. Warum ist sie im Hintergrund? Sie nimmt als Parameter an, wie viele Seiten geschrieben werden sollen. Und nehmen wir an, es werden N Seiten geschrieben. Für eine gewisse Zeit schläft dieser Prozess dann und kommt später zurück, um eine weitere Anzahl von Seiten zu schreiben.
Es ist eine ganz einfache Geschichte. Man kann es mit einem Schwimmbecken vergleichen: Wenn in ein Rohr Wasser hineinfließt, fließt es in ein anderes wieder heraus. Wir haben einen Checkpoint erhalten und wenn nur wenige schmutzige Seiten zur Entsorgung gesendet wurden, wird sich dies nach und nach aus dem Kernel-Puffer pgflush elegant lösen.
Wenn diese schmutzigen Seiten weiter angesammelt werden, erreichen sie 20 %. Danach hat das Betriebssystem Priorität, diese auf die Festplatte zu schreiben, weil ein Stromausfall zu schlimmen Problemen führen kann. Wir würden beispielsweise diese Daten verlieren.
Was ist der Trick? Der Trick besteht darin, dass diese Werte in der modernen Welt, 20 % und 10 % des gesamten Arbeitsspeichers, der auf dem Rechner vorhanden ist, aus Sicht der Durchsatzkapazität jedes Disk-Systems, das Sie haben, völlig absurd sind.
Stellen Sie sich vor, Sie haben 128 GB Arbeitsspeicher. 12,8 GB landen in Ihrem Speichersystem. Egal, welcher Cache oder welches Array Sie dort haben, sie können so viel nicht verarbeiten.

Deshalb empfehlen wir, diese Werte gleich an die Möglichkeiten Ihres RAID-Controllers anzupassen. Hier gibt es sofort eine Empfehlung für einen Controller mit 512 MB Cache.
Es ist alles recht einfach. Man kann vm.dirty_background in Bytes festlegen. Diese Einstellungen heben die vorherigen beiden auf. Entweder wird das Verhältnis standardmäßig verwendet oder, wenn die in Bytes aktiv sind, dann gelten die in Bytes. Da ich jedoch DBA-Berater bin und mit verschiedenen Kunden arbeite, versuche ich, auf alles vorbereitet zu sein. Wenn es also in Bytes ist, dann in Bytes. Niemand hat eine Garantie gegeben, dass ein wohlwollender Administrator dem Server nicht etwas mehr RAM hinzufügt oder ihn neu startet, während die Zahlen gleich bleiben. Berechnen Sie einfach diese Zahlen, um sicherzustellen, dass alles problemlos passt.
Was passiert, wenn Sie nicht eingreifen? Mir wurde gesagt, dass jegliches Flushing effektiv gestoppt wird, aber das ist eigentlich nur eine Redewendung. Das Betriebssystem hat ein großes Problem – es gibt viele schmutzige Seiten, weshalb letztendlich der IO effektiv gestoppt wird, den Ihre Kunden generieren. Das heißt, wenn eine App versucht, eine SQL-Anfrage an die Datenbank zu senden, wartet sie. Jeder IO-Vorgang hat die niedrigste Priorität, weil die Datenbank mit dem Checkpoint beschäftigt ist. Und wann dieser abgeschlossen wird, ist völlig unklar. Wenn Sie den nicht-background Flushing erreicht haben, bedeutet das, dass alle IO-Vorgänge damit beschäftigt sind. Und solange dies nicht abgeschlossen ist, können Sie nichts weiter machen.
Es gibt hier noch zwei wichtige Punkte, die über diesen Bericht hinausgehen. Diese Einstellungen sollten mit den Einstellungen in postgresql.conf übereinstimmen, also mit den Einstellungen für Checkpoints. Und Ihr Speichersystem sollte entsprechend konfiguriert sein. Wenn Sie Cache auf RAID haben, sollte darauf eine Batterie vorhanden sein. Menschen kaufen RAID mit gutem Cache, aber ohne Batterie. Wenn Sie SSDs in RAID haben, sollten diese serverseitig sein und über Kondensatoren verfügen. Hier ist eine ausführliche Checkliste. Über diesen Link finden Sie meinen Bericht zur Konfiguration der Festplattenleistung in PostgreSQL. Alle diese Checklisten sind dort enthalten.

Was das Leben zusätzlich erheblich komplizieren kann, sind zwei Parameter. Sie sind relativ neu. Standardmäßig können sie in verschiedenen Anwendungen aktiviert sein. Wenn sie jedoch falsch eingestellt sind, können sie das Leben nicht weniger erschweren.

Es gibt zwei relativ neue Funktionen. Sie sind bereits in den dritten Versionen der Kerne vorhanden. Das sind sched_migration_cost in Nanosekunden und sched_autogroup_enabled, das standardmäßig auf 1 gesetzt ist.
Und wie beeinflussen sie das Leben negativ? Was ist sched_migration_cost? Der Linux-Scheduler kann einen Prozess von einem CPU auf einen anderen migrieren. Und für PostgreSQL, das Abfragen ausführt, ist es völlig unverständlich, warum eine Migration auf einen anderen CPU stattfinden sollte. Aus Sicht des Betriebssystems ist es vielleicht sinnvoll, wenn Sie Fenster zwischen OpenOffice und dem Terminal wechseln, aber für eine Datenbank ist das äußerst nachteilig. Deshalb ist eine vernünftige Richtlinie, den migration_cost auf einen hohen Wert zu setzen, mindestens mehrere Tausend Nanosekunden.
Was bedeutet das für den Scheduler? Er wird annehmen, dass dieser Prozess während dieser Zeit weiterhin aktiv ist. Das heißt, wenn Sie mit einer langwierigen Transaktion beschäftigt sind, wird der Scheduler dies erkennen. Er wird also annehmen, dass dieser Prozess nicht migriert werden muss, solange der Timeout nicht abgelaufen ist. Wenn der Prozess etwas tut, wird er nicht migriert, sondern weiterhin auf der ihm zugewiesenen CPU arbeiten. Das Ergebnis ist ausgezeichnet.
Ein zweiter Punkt ist das Autogrouping. Es gibt eine gute Idee für spezifische Workloads, die nichts mit modernen Datenbanken zu tun haben: Prozesse nach dem virtuellen Terminal zu gruppieren, von dem aus sie gestartet wurden. Das ist praktisch für bestimmte Aufgaben. In der Praxis ist PostgreSQL ein multiprozessuales System mit Prefork, das von einem einzigen Terminal aus gestartet wird. Sie haben einen Lock-Writer, Checkpoint und alle Ihre Client-Anfragen werden einem Scheduler und einer CPU zugeordnet. Sie werden dort gemeinsam darauf warten, dass der Scheduler frei wird, um sich gegenseitig nicht zu stören und ihn länger zu beanspruchen. Diese Vorgehensweise ist unter solch einer Last völlig unnötig und sollte daher deaktiviert werden.

Mein Kollege Alexey Lesovski hat Tests mit einem einfachen pgbench durchgeführt, bei denen er den migration_cost um einen Faktor erhöht und die Autogroup deaktiviert hat. Der Unterschied bei schlechter Hardware betrug fast 10 %.Es gibt eine Diskussion im Postgres-Forum, in der die Leute Ergebnisse präsentieren, wie solche Änderungen die Abfragegeschwindigkeit beeinflusst haben. Das hatte einen Einfluss von 50 %.Es gibt viele solche Geschichten.

Und zum Schluss noch etwas zur Energiesparpolitik. Es ist gut, dass man Linux jetzt auf Laptops verwenden kann, und es soll angeblich den Akku gut schonen. Aber überraschenderweise kann das auch auf Servern der Fall sein.
Darüber hinaus, wenn Sie Server bei einem Hosting-Anbieter mieten, kümmern sich die 'freundlichen' Hosting-Dienstleister nicht darum, dass Sie eine bessere Leistung erhalten. Ihre Aufgabe ist es, die Hardware so effizient wie möglich zu nutzen. Daher können sie standardmäßig im Betriebssystem den Laptop-Energiesparmodus aktivieren.
Wenn Sie auf einem Server mit einer stark belasteten Datenbank dieses System verwenden, sollten Sie acpi_cpufreq + performance wählen. Selbst mit ondemand werden bereits Probleme auftreten.
Intel_pstate – ist ein etwas anderer Treiber. Aktuell wird dieser bevorzugt, da er neuer und stabiler ist.
Dementsprechend ist der Governor nur auf Performance eingestellt. Ondemand, powersave und ähnliche Optionen sind hier nicht relevant.
Die Ergebnisse von explain analyze in PostgreSQL können sich um mehrere Größenordnungen ändern, wenn powersave aktiviert ist, da der CPU unter diesen Bedingungen auf unvorhersehbare Weise geplant wird.
Diese Einstellungen können standardmäßig aktiviert sein. Überprüfen Sie sorgfältig, ob sie nicht bereits standardmäßig eingeschaltet sind. Das könnte ein großes Problem darstellen.

Zum Schluss möchte ich mich bei unserem DBA-Team von PostgreSQL-Consulting bedanken, insbesondere bei Max Boguk und Alexey Lesovski, die täglich Erfahrungen sammeln. Wir streben danach, unseren Kunden die bestmögliche Performance zu bieten. Es ist wie bei den Sicherheitsanweisungen im Flugwesen – alles ist aus bitteren Erfahrungen heraus geschrieben. Jede dieser Schrauben wurde durch ein Problem erkannt. Ich teile diese Erkenntnisse gern mit Ihnen.
Fragen:
Danke! Wenn ein Unternehmen beispielsweise Kosten sparen möchte und sowohl eine Datenbank als auch die Anwendungslogik auf einem Server betreiben will, oder wenn es dem modernen Trend zu Microservice-Architekturen folgt, in denen PostgreSQL in einem Container läuft, was ist dann der Trick? Sysctl wirkt sich global auf den gesamten Kernel aus. Ich habe noch nie gehört, dass sysctl irgendwie virtualisiert wurden, sodass sie im Container getrennt funktionieren. Es gibt nur cgroups und dort gibt es nur eine teilweise Kontrolle. Wie kann man damit leben? Oder wenn Sie Leistung wollen, sollten Sie PostgreSQL auf einem dedizierten Server betreiben und es optimieren?
Wir haben Ihre Frage auf etwa drei Arten beantwortet. Wenn es sich nicht um einen dedizierten Server handelt, den man optimieren kann usw., dann entspannen Sie sich, es wird auch ohne diese Einstellungen gut laufen. Wenn die Last so hoch wird, dass diese Einstellungen nötig sind, werden Sie früher zu einem dedizierten Server kommen, als zu diesen Einstellungen.
Was ist das Problem? Wenn es sich um eine virtuelle Maschine handelt, werden Sie wahrscheinlich auf zahlreiche Probleme stoßen, wie beispielsweise inkonsistente Disklatenzen bei den meisten virtuellen Maschinen. Selbst wenn die Datentransfergeschwindigkeit gut ist, kann eine fehlerhafte Eingabe-/Ausgabe-Transaktion, die die durchschnittliche Bandbreite nicht merklich beeinflusst, während eines Checkpoints oder beim Schreiben in das WAL erfolgen, was die Datenbank erheblich belasten wird. Und Sie werden dies früher bemerken, als Sie denken.
Wenn Sie NGINX auf demselben Server betreiben, wird das gleiche Problem auftreten. Es wird um den gemeinsam genutzten Speicher konkurrieren. Und Sie werden nicht vor den beschriebenen Problemen sicher sein.
Auf der anderen Seite werden einige dieser Parameter weiterhin für Sie relevant sein. Zum Beispiel sollten Sie mit sysctl den dirty_ratio einstellen, um extreme Werte zu vermeiden – das wird auf jeden Fall helfen. So oder so wird Ihre Interaktion mit der Disk stattfinden. Und das wird auf eine falsche Weise geschehen. Die Parameter, die ich gezeigt habe, sind Standardwerte. In jedem Fall ist es besser, diese zu ändern.
Mit NUMA können Probleme auftreten. VmWare funktioniert beispielsweise gut mit NUMA bei genau entgegengesetzten Einstellungen. Hier muss man zwischen einem physischen Server und einem virtuellen Server wählen.
Ich habe eine Frage zu Amazon AWS. Sie haben vorinstallierte Images. Eines davon heißt Amazon RDS. Gibt es dort irgendwelche benutzerdefinierten Einstellungen für deren Betriebssystem?
Es gibt Einstellungen, aber es sind andere Einstellungen. Hier konfigurieren wir das Betriebssystem in Bezug darauf, wie die Datenbank es nutzen wird. Dort gibt es Parameter, die bestimmen, in welche Richtung wir jetzt gehen, diese Art von Shaping. Das heißt, wir benötigen so viele Ressourcen, die werden wir jetzt ausschöpfen. Danach passt Amazon RDS diese Ressourcen an, und die Leistung sinkt. Es gibt verschiedene Geschichten darüber, wie Leute mit diesem Thema experimentieren. Manchmal sogar recht erfolgreich. Aber das hat nichts mit den Betriebssystemeinstellungen zu tun. Es ist eher wie Cloud-Hacking. Das ist eine andere Geschichte.
Warum bringen transparente große Seiten keinen Effekt im Vergleich zu großen TLB?
Sie geben es nicht. Das kann man auf viele Arten erklären, aber letztendlich geben sie es einfach nicht. Was ist die Geschichte von PostgreSQL? Beim Start weist es ein großes Stück Shared Memory zu. Ob dies transparent ist oder nicht, spielt keine Rolle. Die Tatsache, dass Speicher zu Beginn zugewiesen wird, erklärt alles. Wenn viel Speicher vorhanden ist und der Shared Memory-Segment neu aufgebaut werden muss, sind transparente große Seiten relevant. In PostgreSQL ist es einfach beim Start in einem großen Stück zugewiesen, und dann passiert nichts Besonderes mehr. Natürlich könnte man es verwenden, aber es besteht die Gefahr, dass der Shared Memory beschädigt wird, wenn es wieder zugewiesen wird. PostgreSQL weiß darüber jedoch nichts.
Quelle: habr.com
