PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verwalten des Einfrierens in PostgreSQL

Postgres enthält einen beweglichen Ereignishorizont, der ungefähr 2 Milliarden Transaktionen vor oder hinter der aktuellen Transaktions-ID liegt. Transaktionen, die bis zu 2 Milliarden vor oder mehr als 2 Milliarden hinter der aktuellen Transaktions-ID liegen, gelten als in der Zukunft liegend und sind daher für aktuelle Transaktionen unsichtbar.

Postgres vermeidet diesen katastrophalen Datenverlust, indem es alte Zeilen speziell markiert, sodass sie unabhängig davon, wo sie sich in Bezug auf die aktuelle Transaktions-ID befinden, sichtbar sind.

Einfrieren ist dieser Prozess des Markierens alter Live-Tupel (d. H. Datenbankzeilen), damit sie nicht vom sich bewegenden Ereignishorizont überrollt werden, der sie sonst als in der Zukunft erscheinen lassen würde. Dies steht im Gegensatz zum Vakuumieren, bei dem Speicherplatz freigegeben wird, der von alten toten Tupeln verbraucht wird, die für keine Transaktion mehr sichtbar sind.

Beide Prozesse werden durch Vakuum gesteuert.

Es gibt eine Reihe von Einstellungen, die bestimmen, wie das Einfrieren durchgeführt wird.

Zuerst vacuum_freeze_min_age regelt, ob ein Tupel eingefroren wird oder nicht, während das Vakuum bereits auf einer Seite nachschaut, um zu sehen, ob es tote Tupel gibt, die bereinigt werden können. Tupel älter als vacuum_freeze_min_age wird in diesem Fall eingefroren. Wenn Sie diesen Wert auf einen niedrigen Wert setzen, bedeutet dies, dass später weniger Arbeit zu erledigen ist, jedoch auf Kosten zusätzlicher Anstrengungen sowohl bei der CPU- als auch bei der E/A- oder WAL-Aktivität. Im Allgemeinen möchten Sie dieses Set wahrscheinlich auf Transaktionen im Wert von mindestens einigen Stunden setzen. Nehmen wir an, Sie erwarten dauerhaft bis zu 2000 Transaktionen pro Sekunde. 2000 TPS sind 7,2 Millionen Transaktionen pro Stunde. Daher könnte eine ziemlich aggressive Einstellung für diesen Fall beispielsweise 20 m sein. Die Standardeinstellung ist 50 m. Ähnlich für vacuum_multixact_freeze_min_age . Beachten Sie, dass die Zähler transaction_id und multixid unabhängig voneinander sind – Sie müssen beide im Auge behalten.

Zweitens gibt es vacuum_freeze_table_age und vacuum_multixact_freeze_table_age . Diese Einstellungen legen fest, wann die Selbstbereinigung nicht nur Seiten mit möglicherweise toten Zeilen betrachtet, sondern alle Seiten mit möglicherweise nicht eingefrorenen Zeilen. Die Standardwerte für diese Einstellungen sind 150 m. Wenn Sie vacuum_freeze_min_age reduziert haben genug, in vielen Fällen hat dieses aggressivere Vakuum wenig oder gar keine Arbeit zu tun. In jedem Fall ist dieser Prozess nicht mehr so ​​​​beschäftigt wie früher, da moderne Versionen von Postgres (9.6 und höher) eine Karte von Seiten führen, auf denen alle Tupel eingefroren sind, und nur die Seiten besuchen, die nicht alle eingefroren sind. Das bedeutet, dass dies kein vollständiger Tabellenscan mehr ist.

Zuletzt gibt es noch autovacuum_freeze_max_age . Wenn das letzte Mal, dass die Tabelle vollständig nach nicht eingefrorenen Zeilen durchsucht wurde, mehr als diese Anzahl an Transaktionen zurückliegt, startet Autovacuum ein Anti-Wraparound-Vakuum auf der Tabelle. Der Standardwert ist 200 m. Ähnlich für autovacuum_multixact_freeze_max_age für die der Standardwert 400 m ist. Das ist etwas, das Sie wirklich vermeiden möchten. Es gibt zwei Dinge, die getan werden können. Erstens ist es sehr üblich, diese Einstellungen auf etwa 1 Milliarde zu erhöhen, um sich mehr Spielraum zu verschaffen, insbesondere auf Systemen, die viele Transaktionen verbrauchen. Sie könnten es mehr machen, aber Sie möchten viel Transaktionsraum zwischen Ihrem ältesten Tupel und dem Ereignishorizont haben. Zweitens ist es wichtig, Ihre Systeme zu überwachen und Abhilfemaßnahmen zu ergreifen, bevor Datenbanken darauf stoßen. Diese Abhilfemaßnahme umfasst häufig manuelles Staubsaugen.

Ein Problem, das auftreten kann, ist, wenn Sie DDL haben, das dazu führt, dass sich das normale (d. h. kein Anti-Wraparound) Autovacuum selbst abbricht. Wenn Sie dies oft genug tun, wird schließlich ein Anti-Wraparound-Vakuum erzwungen, und jede DDL stellt sich dann hinter den Vakuumprozess, was wiederum jede weitere DML blockiert. In diesem Stadium ist Ihre Tabelle effektiv unlesbar, bis das Vakuum beendet ist. Dies hängt vom Nutzungsmuster Ihrer Datenbank ab, aber dies ist nicht nur eine theoretische Möglichkeit, und Postgres-Bereitstellungen und DBAs müssen dies berücksichtigen.

Die Überwachung Ihres Datenbank-Clusters ist für die Verwaltung von entscheidender Bedeutung. Insbesondere müssen Sie die datfrozenxid überwachen und datminmxid jeder Datenbank im Cluster, und wenn diese zu alt werden, ergreifen Sie Abhilfemaßnahmen, bevor ein Anti-Wraparound-Vakuum erforderlich ist. Oft liegt das Problem bei einer oder wenigen Tabellen in der Datenbank. Welche das Problem sind, kann durch Untersuchen der relfrozenxid entdeckt werden und relminmxid der Tabellen in der Datenbank. Das age() und mxid_age() Funktionen sind nützlich, um das Alter von Transaktions-ID- bzw. Multixid-Zählern zu ermitteln.

Das Einfrieren ist nichts, was Sie vermeiden können, es ist eine wesentliche Wartungsaktivität in Postgres, die aktiv verwaltet werden muss.