DBAtlas · Atlas de operações de banco de dados

Crise de XID wraparound / autovacuum no Postgres

Sintoma

'database is not accepting commands to avoid wraparound data loss'; o autovacuum não consegue acompanhar, o datfrozenxid está envelhecendo.

1. Entenda a urgência

Os IDs de transação do PostgreSQL são de 32 bits; quando se aproximam do esgotamento, o servidor PARA AS ESCRITAS para evitar perda de dados. É uma situação crítica e sensível ao tempo. A boa notícia: tem solução; exige disciplina, não pânico.

2. Meça o quão perto você está

Levante a idade do XID não congelado mais antigo de cada banco; a proximidade de autovacuum_freeze_max_age (padrão 200M) mostra o perigo.

PostgreSQL

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

3. Encontre as tabelas mais antigas

O problema geralmente vem de algumas tabelas grandes/muito escritas; concentre-se nos valores de relfrozenxid mais antigos.

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. Remova o que está bloqueando o VACUUM

Transações longas abertas, replication slots abandonados e prepared transactions bloqueiam a limpeza (freeze). Encontre-os e resolva — caso contrário o VACUUM não avança, por mais tempo que rode.

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. Execute um FREEZE agressivo

Quando os bloqueadores sumirem, force o congelamento começando pelas tabelas mais antigas. Mesmo que o servidor tenha parado de atribuir novos IDs de transação, não passe para o modo single-user (postgres --single): a documentação atual do PostgreSQL diz que ele não é mais necessário e deve ser evitado. Conectar como superusuário no modo normal e executar VACUUM é suficiente; no PG14+, o mecanismo failsafe do VACUUM entra em ação conforme o wraparound se aproxima.

PostgreSQL

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

6. Definitivo: reforce e monitore o autovacuum

Aumente autovacuum_vacuum_cost_limit, reduza autovacuum_naptime e defina parâmetros de armazenamento específicos nas tabelas muito escritas. Configure um alerta para age(datfrozenxid); nunca mais passe por esta crise.

Abrir no DBAtlas →