DBAtlas · Atlas de operaciones de bases de datos

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=4

6. 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.

Abrir en DBAtlas →