DBAtlas · Atlas d'exploitation des bases de données

Crise XID wraparound / autovacuum dans Postgres

Symptôme

'database is not accepting commands to avoid wraparound data loss' ; autovacuum ne suit pas, datfrozenxid vieillit.

1. Mesurez l'urgence

Les identifiants de transaction PostgreSQL sont sur 32 bits ; à l'approche de leur épuisement, le serveur ARRÊTE LES ÉCRITURES pour éviter la perte de données. C'est une situation critique et urgente. La bonne nouvelle : elle se résout ; il faut de la méthode, pas de la panique.

2. Mesurez la proximité de la limite

Extrayez l'âge du plus ancien XID non gelé pour chaque base ; la proximité d'autovacuum_freeze_max_age (200M par défaut) indique le danger.

PostgreSQL

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

3. Trouvez les tables les plus anciennes

Le problème vient généralement de quelques grandes tables/tables très écrites ; concentrez-vous sur les relfrozenxid les plus anciens.

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. Levez ce qui bloque VACUUM

Les longues transactions ouvertes, les slots de réplication abandonnés et les transactions préparées bloquent le nettoyage (freeze). Trouvez-les et résolvez-les, sinon VACUUM ne progresse pas, quelle que soit sa durée.

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. Lancez un FREEZE agressif

Une fois les blocages levés, forcez le gel en commençant par les tables les plus anciennes. Même si le serveur a cessé d'attribuer de nouveaux identifiants de transaction, ne passez pas en mode mono-utilisateur (postgres --single) : la documentation actuelle de PostgreSQL indique qu'il n'est plus nécessaire et doit être évité. Se connecter en superuser en mode normal et lancer VACUUM suffit ; en PG14+, le mécanisme failsafe de VACUUM s'active à l'approche du wraparound.

PostgreSQL

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

6. Définitif : renforcez et surveillez autovacuum

Augmentez autovacuum_vacuum_cost_limit, réduisez autovacuum_naptime et définissez des paramètres de stockage spécifiques sur les tables très écrites. Mettez en place une alerte sur age(datfrozenxid) ; ne revivez jamais cette crise.

Ouvrir dans DBAtlas →