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=46. 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.