DBAtlas · Atlas für Datenbankbetrieb

Postgres XID-Wraparound / Autovacuum-Krise

Symptom

'database is not accepting commands to avoid wraparound data loss'; autovacuum kommt nicht hinterher, datfrozenxid altert.

1. Die Dringlichkeit verstehen

PostgreSQL-Transaktions-IDs sind 32-Bit-Werte; nähern sie sich der Erschöpfung, STOPPT der Server SCHREIBVORGÄNGE, um Datenverlust zu verhindern. Das ist eine kritische, zeitkritische Lage. Die gute Nachricht: Sie ist lösbar; es braucht Disziplin, keine Panik.

2. Messen, wie nah du an der Grenze bist

Ermittle für jede Datenbank das Alter der ältesten nicht eingefrorenen XID; die Nähe zu autovacuum_freeze_max_age (Standard 200M) zeigt die Gefahr.

PostgreSQL

SELECT datname, age(datfrozenxid) AS xid_age
FROM pg_database ORDER BY xid_age DESC;

3. Die ältesten Tabellen finden

Das Problem geht meist von wenigen großen bzw. häufig beschriebenen Tabellen aus; konzentriere dich auf die ältesten relfrozenxid-Werte.

PostgreSQL

SELECT relname, age(relfrozenxid) AS xid_age
FROM pg_class WHERE relkind IN ('r','m','t')
ORDER BY xid_age DESC LIMIT 20;

4. Beseitigen, was VACUUM blockiert

Lang offene Transaktionen, verwaiste Replication Slots und Prepared Transactions blockieren das Aufräumen (Freeze). Finde und löse sie – sonst kommt VACUUM nicht voran, egal wie lange es läuft.

PostgreSQL

SELECT pid, now()-xact_start AS age, state FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY age DESC;
SELECT slot_name, active FROM pg_replication_slots WHERE NOT active;
SELECT * FROM pg_prepared_xacts;

5. Ein aggressives FREEZE ausführen

Sind die Blocker beseitigt, erzwinge das Einfrieren, beginnend mit den ältesten Tabellen. Selbst wenn der Server keine neuen Transaktions-IDs mehr vergibt, wechsle nicht in den Single-User-Modus (postgres --single): Laut aktueller PostgreSQL-Dokumentation ist er nicht mehr nötig und sollte vermieden werden. Es genügt, sich im normalen Modus als Superuser zu verbinden und VACUUM auszuführen; ab PG14+ greift der Failsafe-Mechanismus von VACUUM, wenn der Wraparound näher rückt.

PostgreSQL

VACUUM (FREEZE, VERBOSE) oldest_table;
-- Entire database: vacuumdb --all --freeze --jobs=4

6. Dauerhaft: Autovacuum stärken und überwachen

Erhöhe autovacuum_vacuum_cost_limit, senke autovacuum_naptime und setze für stark beschriebene Tabellen tabellenspezifische Storage-Parameter. Richte einen Alarm auf age(datfrozenxid) ein; erlebe diese Krise nie wieder.

In DBAtlas öffnen →