Postgres: XID wraparound / crisis de autovacuum
Síntoma
'database is not accepting commands to avoid wraparound data loss'; autovacuum no da abasto, datfrozenxid envejece.
1. Evalúe la urgencia
Los ID de transacción de PostgreSQL son de 32 bits; cuando se acercan al agotamiento, el servidor DETIENE LAS ESCRITURAS para evitar pérdida de datos. Es una situación crítica y urgente. La buena noticia: tiene solución; requiere disciplina, no pánico.
2. Mida qué tan cerca está
Obtenga la edad del XID no congelado más antiguo de cada base de datos; la cercanía a autovacuum_freeze_max_age (200M por defecto) indica el riesgo.
PostgreSQL
SELECT datname, age(datfrozenxid) AS xid_age
FROM pg_database ORDER BY xid_age DESC;3. Encuentre las tablas más antiguas
El problema suele provenir de unas pocas tablas grandes o con escritura frecuente; céntrese en los valores de relfrozenxid más antiguos.
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. Elimine lo que bloquea VACUUM
Las transacciones abiertas durante mucho tiempo, los replication slots abandonados y las transacciones preparadas impiden la limpieza (freeze). Encuéntrelos y resuélvalos; de lo contrario VACUUM no avanza por mucho que se ejecute.
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. Ejecute un FREEZE agresivo
Una vez eliminados los bloqueadores, fuerce el congelamiento empezando por las tablas más antiguas. Aunque el servidor haya dejado de asignar nuevos ID de transacción, no pase a modo monousuario (postgres --single): la documentación actual de PostgreSQL indica que ya no es necesario y que debe evitarse. Basta con conectarse como superusuario en modo normal y ejecutar VACUUM; en PG14+, el mecanismo failsafe de VACUUM se activa al acercarse el wraparound.
PostgreSQL
VACUUM (FREEZE, VERBOSE) oldest_table;
-- Entire database: vacuumdb --all --freeze --jobs=46. Permanente: refuerce y monitoree autovacuum
Aumente autovacuum_vacuum_cost_limit, reduzca autovacuum_naptime y defina parámetros de almacenamiento específicos en las tablas con mucha escritura. Configure una alerta sobre age(datfrozenxid); no vuelva a pasar por esta crisis.