Überraschen Sie fsync () PostgreSQL

DBMS-Entwickler befürchten zwangsläufig, dass die Daten sicher dauerhaft gespeichert werden. Als die PostgreSQL-Community feststellte, dass die Art und Weise, wie der Kernel mit E / A-Fehlern umgeht, zu Datenverlust führen kann, ohne dass Fehler an den Benutzerbereich gemeldet werden, kam es zu großer Unzufriedenheit. Das Problem, das durch die Tatsache verschlimmert wird, dass PostgreSQL gepufferte E / A ausführt, ist nicht nur unter Linux zu finden und wird auch dort nicht einfach zu lösen sein.

Craig Ringer meldete das Problem erstmals Ende März an die Mailingliste von pgsql-hackers. Kurz gesagt, PostgreSQL geht davon aus, dass ein erfolgreicher Aufruf von fsync() anzeigt, dass alle seit dem letzten erfolgreichen Aufruf aufgezeichneten Daten sicher in einen dauerhaften Speicher übertragen wurden. Wenn gepufferte E / A-Schreibvorgänge aufgrund eines Hardwarefehlers fehlschlagen, reagieren Dateisysteme unterschiedlich. Bei diesem Verhalten werden jedoch normalerweise Daten auf den entsprechenden Seiten gelöscht und als sauber markiert. Daher werden Leseblöcke, die gerade geschrieben wurden, höchstwahrscheinlich etwas anderes zurückgeben, jedoch keine aufgezeichneten Daten.

Was ist mit der Fehlerberichterstattung? Vor einem Jahr umfasste der Gipfel zum Linux-Dateisystem-, Speicher- und Speicherverwaltungsgipfel (LSFMM) eine Sitzung zur Fehlerberichterstattung, in der alles als „Chaos“ bezeichnet wurde. Fehler können leicht verloren gehen, sodass sie von keiner Anwendung jemals gesehen werden. Einige in 4.13 enthaltene Patches haben die Situation während des Entwicklungszyklus etwas verbessert (und in 4.16 wurden einige Änderungen vorgenommen, um sie weiter zu verbessern). Es gibt jedoch Möglichkeiten, Fehlerbenachrichtigungen zu verlieren, wie unten beschrieben. Wenn dies auf einem PostgreSQL-Server geschieht, kann dies zu einer automatischen Beschädigung der Datenbank führen.

PostgreSQL-Entwickler waren unglücklich. Tom Lane beschrieb dies als " Hirnschädigung des Kerns ", während Robert Haas es " 100% dumm " nannte. Zu Beginn der Diskussion haben die PostgreSQL-Entwickler ganz klar verstanden, wie der Kernel ihrer Meinung nach funktionieren sollte: Seiten, die nicht geschrieben werden konnten, sollten in einem "schmutzigen" Zustand gespeichert werden (für nachfolgende Versuche) und der entsprechende Dateideskriptor sollte übersetzt werden Permanenter Fehlerstatus, damit der PostgreSQL-Server das Problem nicht überspringen kann.

Wo ist etwas schief gelaufen?


Doch noch bevor die Kernel-Community in die Diskussion eintrat, wurde klar, dass die Situation nicht so einfach war, wie es scheinen mag. Thomas Munro sagte, dass Linux in diesem Verhalten nicht einzigartig ist; OpenBSD und NetBSD melden möglicherweise auch keine Schreibfehler im Benutzerbereich. Und wie sich herausstellte, erschwert die Art und Weise, wie PostgreSQL mit gepufferten E / A-Operationen umgeht, das Bild erheblich.

Dieser Mechanismus wurde von Haas ausführlich beschrieben . Ein PostgreSQL-Server arbeitet als eine Reihe von Prozessen, von denen viele E / A für Datenbankdateien ausführen können. Der fsync() wird jedoch in einem einzigen Checkpointer-Prozess ("Checkpointer" -Prozess) ausgeführt, bei dem der Festplattenspeicher in einem konsistenten Zustand gehalten wird, um Fehler zu beheben. Checkpointer hält normalerweise nicht alle relevanten Dateien offen, daher muss die Datei häufig geöffnet werden, bevor fsync() . Hier tritt das Problem auf: Selbst in Kernel 4.13 und späteren Versionen werden beim Checkpointer keine Fehler angezeigt, die vor dem Öffnen der Datei aufgetreten sind. Wenn vor dem Aufruf von open() checkpointer-a etwas Schlimmes passiert, gibt der nächste Aufruf von fsync() Erfolg zurück. Es gibt verschiedene Möglichkeiten, einen E / A-Fehler außerhalb von fsync() . Beispielsweise kann der Kernel beim Zurückschreiben im Hintergrund auf einen von ihnen stoßen. Jemand, der sync() aufruft, kann auch auf einen E / A-Fehler stoßen und den resultierenden Fehlerzustand „absorbieren“.

Haas beschrieb dieses Verhalten als nicht in der Lage, die Erwartungen von PostgreSQL zu erfüllen:
Alles, was Sie (oder jemand) haben, ist im Grunde eine unbewiesene Annahme, dass
Welche Dateideskriptoren für einen bestimmten Fehler relevant sein können, aber es kam vor, dass PostgreSQL nie mit ihm übereinstimmte. Sie können weiterhin sagen, dass das Problem in unseren Vermutungen liegt, aber es scheint mir falsch anzunehmen, dass wir das einzige Programm sind, das sie jemals durchgeführt hat.

Infolgedessen hat Joshua Drake die Konversation in die Entwicklungsliste für ext4 verschoben , einschließlich eines Teils der Kernel-Entwicklergemeinschaft. Dave Chinner beschrieb dieses Verhalten schnell als "ein Rezept für eine Katastrophe, insbesondere bei plattformübergreifendem Code, bei dem sich jede Betriebssystemplattform anders verhält und fast nie den Erwartungen entspricht ". Stattdessen erklärte Ted Tso , warum die betroffenen Seiten nach einem E / A-Fehler als sauber markiert werden. Kurz gesagt, die häufigste Ursache für E / A-Fehler ist, dass der Benutzer das USB-Laufwerk zum falschen Zeitpunkt auswirft. Wenn ein Prozess viele Daten auf diese Festplatte kopiert, führt dies dazu, dass sich schmutzige Seiten im Speicher ansammeln, möglicherweise bis zu dem Punkt, dass das System nicht über genügend Speicher für andere Aufgaben verfügt. Daher können diese Seiten nicht gespeichert werden und werden gelöscht, wenn der Benutzer möchte, dass das System nach einem solchen Ereignis weiterhin verwendet werden kann.

Sowohl Chinner als auch Tso und andere sagten, PostgreSQL habe die richtige Lösung - wechseln Sie zu Direct I / O (DIO). Die Verwendung von DIO bietet eine bessere Kontrolle über das Zurückschreiben und die E / A im Allgemeinen. Dies umfasst den Zugriff auf Informationen darüber, welche E / A-Vorgänge möglicherweise fehlgeschlagen sind. Andres Freund hat wie eine Reihe anderer PostgreSQL-Entwickler anerkannt, dass DIO die beste langfristige Lösung ist. Er merkte aber auch an, dass man nicht erwarten sollte, dass Entwickler tief in die Umsetzung dieser Aufgabe eintauchen. In der Zwischenzeit sagte er , dass es andere Programme gibt (er erwähnte dpkg), die ebenfalls für dieses Verhalten anfällig sind.

Auf dem Weg zu einer kurzfristigen Lösung


Während der Diskussion wurde der Idee große Aufmerksamkeit geschenkt, dass ein Schreibfehler dazu führen sollte, dass die betroffenen Seiten in ihrem schmutzigen Zustand im Speicher gespeichert werden. PostgreSQL-Entwickler haben sich jedoch schnell von dieser Idee entfernt und sie nicht gefordert. Was sie wirklich brauchen, ist letztendlich ein zuverlässiger Weg, um herauszufinden, ob etwas schief gelaufen ist. In diesem Sinne können die üblichen PostgreSQL-Fehlerbehandlungsmechanismen dies handhaben. In seiner Abwesenheit kann jedoch wenig getan werden.

Irgendwann in der Diskussion erwähnte Tso , dass Google über einen eigenen Mechanismus zur Behandlung von E / A-Fehlern verfügt. Der Kernel wurde angewiesen, E / A-Fehler über den Netlink-Socket zu melden. Der dedizierte Prozess erhält diese Benachrichtigungen und reagiert entsprechend. Dieser Mechanismus hat dies jedoch nie am Eingang getan. Freind wies darauf hin, dass dieser Mechanismus für PostgreSQL "ideal" wäre, so dass er in naher Zukunft gemeinfrei erscheinen könnte.

In der Zwischenzeit dachte Jeff Leighton über eine andere Idee nach: ein Flag im Superblock des Dateisystems zu setzen, wenn ein E / A-Fehler auftritt. Ein Aufruf von syncfs() dann dieses Flag und gibt einen Fehler zurück, wenn es gesetzt wurde. Der PostgreSQL-Checkpointer kann regelmäßig syncfs() aufrufen, um nach Fehlern im Dateisystem zu syncfs() , das die Datenbank enthält. Freund stimmte zu, dass dies eine praktikable Lösung für das Problem sein könnte.

Natürlich wird ein solcher Mechanismus nur in neuen Kerneln auftreten. In der Zwischenzeit werden PostgreSQL-Installationen normalerweise auf älteren Kerneln ausgeführt, die von Unternehmensdistributionen unterstützt werden. In diesen Kerneln scheint es nicht einmal die Verbesserungen zu geben, die in 4.13 enthalten waren. Für diese Systeme kann wenig getan werden, um PostgreSQL bei der Erkennung von E / A-Fehlern zu unterstützen. Es kann ausreichen, einen Daemon zu starten, der das Systemprotokoll durchsucht und dort nach E / A-Fehlermeldungen sucht. Nicht die eleganteste Lösung, und es wird durch die Tatsache erschwert, dass verschiedene Blocktreiber und Dateisysteme Fehler in der Regel auf unterschiedliche Weise melden. Dies ist jedoch möglicherweise die beste verfügbare Option.

Der nächste Schritt dürfte eine Diskussion auf der LSFMM 2018 am 23. April sein. Wenn Sie Glück haben, gibt es eine Lösung, die für Interessenten funktioniert. Eine Sache, die sich jedoch nicht ändern wird, ist die einfache Tatsache, dass es schwierig ist, Fehler richtig zu behandeln.

Source: https://habr.com/ru/post/de472684/


All Articles