Como planejar e executar rollback seguro ao atualizar versão major do PostgreSQL (12→14) em produção com réplica de leitura — guia prático
Por Kevin Marcondes · Publicado em · 10 min de leitura
Guia: como planejar e executar rollback seguro ao atualizar versão major do PostgreSQL 12→14 em produção com réplica de leitura. Você verá pré‑requisitos, quando usar pg_upgrade ou replicação lógica, como conduzir o cutover e como reverter com segurança se algo sair do esperado — reduzindo downtime e risco de perda de dados com um plano simples e ensaiado.
Cenário, riscos e objetivo do plano de rollback
Em upgrades major do PostgreSQL, a replicação física não funciona entre versões diferentes. Sua réplica de leitura 12 não seguirá um primário 14. Por isso, o plano precisa considerar como migrar, cortar o tráfego e voltar rápido.
O objetivo é: atualizar para 14 com o mínimo de indisponibilidade, manter um caminho de retorno claro e documentado, e reduzir perda de dados caso seja necessário reverter.
Capacidade e conexões importam no dia do corte. Se o pool estourar, você pode enfrentar fila e timeouts. Veja práticas em como diagnosticar e resolver 'Too many connections'.
- A réplica 12 não pode “virar” 14 e continuar seguindo o primário 12.
- Rollback seguro requer manter o cluster 12 íntegro até confirmar estabilidade no 14.
- Sem replicação reversa configurada, rollback pode implicar perda dos writes feitos após o corte.
- Planeje janela de manutenção curta com mudanças congeladas (freeze de DDL).
Pré‑requisitos e checagens críticas antes do upgrade
Faça um inventário do ambiente e reduza incertezas. Tenha backups testados e um ponto de recuperação (PITR) viável. Confirme espaço em disco para manter o cluster 12 intacto enquanto o 14 estabiliza.
Valide: extensões compatíveis, parâmetros, longas transações, chaves estrangeiras desabilitadas, replicação lógica habilitável (se optar por ela), e TTL de DNS/rotas para um flip rápido. Ajuste o pooler para reconexão suave.
Abaixo, consultas úteis para mapear extensões, sessões longas e configuração de WAL/slots.
- Backups completos + restauração ensaiada (PITR).
- Espaço livre para um cluster 14 ao lado do 12.
- Freeze de DDL e change freeze no app durante a janela.
- TTL de DNS/rotas reduzido com antecedência.
- Extensões e versões revisadas.
- Pooler (PgBouncer) preparado para migração.
-- Extensões instaladas
SELECT extname, extversion FROM pg_extension ORDER BY 1;
-- Transações longas (potencial bloqueio no corte)
SELECT pid, usename, xact_start, state, query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL AND state <> 'idle'
ORDER BY xact_start;
-- Nível de WAL e slots (para replicação lógica)
SHOW wal_level; -- deve ser 'logical' para pub/sub
SHOW max_replication_slots;
SHOW max_wal_senders;
Estratégias com réplica: qual caminho escolher
Escolha a abordagem considerando downtime, complexidade de rollback e recursos. A réplica de leitura ajuda a criar um clone consistente para testes ou como base do 14, mas você precisará quebrar o seguimento em algum momento.
| Estratégia | Downtime | Rollback | Quando usar | Observações |
|---|---|---|---|---|
| A) pg_upgrade em cópia do cluster 12 | Minuto(s) a baixa hora(s) (corte) | Simples: parar 14 e voltar 12 (perda de writes pós‑corte) | Ambientes com janela curta e aceitação de rollback com possível perda mínima | Evite --link; mantenha o 12 intacto até estabilizar o 14 |
| B) Replicação lógica 12→14 (pub/sub) | Baixo a muito baixo | Médio: pode voltar ao 12; para zero perda exige replicação reversa ou bloqueio de writes no smoke | Necessário reduzir downtime e validar 14 com dados reais | Exige wal_level=logical e tratar tabelas sem PK/replicação |
| C) Dump/restore (pg_dump/pg_restore) | Alto | Simples: não cortar se houver falhas | Bancos menores e tolerância a parada | Mais simples, mas com indisponibilidade maior |
Plano A: pg_upgrade usando a réplica (sem --link)
Use a réplica como base do 14 sem arriscar o primário 12. Não use --link se você precisa de rollback garantido; ele altera arquivos do cluster de origem.
Resumo: pare a réplica 12, copie o datadir para um novo local, inicialize o 14, rode pg_upgrade, teste, corte, e só então desligue o 12 depois da janela de observação.
- Parar réplica 12 e garantir consistência.
- Clonar datadir para nova pasta/disco.
- initdb do 14 e pg_upgrade --check.
- Executar pg_upgrade e pós‑análise (analyze/vacuum).
- Cutover curto: apontar app para o 14.
- Manter 12 desligado e intacto para rollback.
# Parar a réplica 12 (ajuste caminhos conforme seu ambiente)
/path/to/old/bin/pg_ctl -D /pgdata/12/replica stop
# Clonar dados da réplica para área do upgrade (cópia completa)
rsync -aH --delete /pgdata/12/replica/ /pgdata/12/upgrade-copy/
# Inicializar cluster 14
/path/to/new/bin/initdb -D /pgdata/14/main
# Verificação prévia
/path/to/new/bin/pg_upgrade \
--old-datadir=/pgdata/12/upgrade-copy \
--new-datadir=/pgdata/14/main \
--old-bindir=/path/to/old/bin \
--new-bindir=/path/to/new/bin \
--check
# Executar upgrade (sem --link)
/path/to/new/bin/pg_upgrade \
--old-datadir=/pgdata/12/upgrade-copy \
--new-datadir=/pgdata/14/main \
--old-bindir=/path/to/old/bin \
--new-bindir=/path/to/new/bin
Plano B: replicação lógica 12→14 para reduzir downtime
Com publicação/assinatura, o 14 recebe dados do 12 enquanto você valida performance. Requisitos: wal_level=logical, PK nas tabelas replicadas, lidar com sequências e DDL. Para rollback sem perda, mantenha writes bloqueados por um período de smoke ou implemente replicação reversa com cuidado.
- Habilitar wal_level=logical no 12 e reiniciar.
- Criar publicação no 12 (filtre tabelas temporárias).
- Inicializar 14 e criar assinatura apontando para o 12.
- Acompanhar sincronização e lag.
- Ensaiar o corte: bloquear writes, esperar catch‑up e mudar endpoint.
-- No 12 (primário)
ALTER SYSTEM SET wal_level = 'logical';
ALTER SYSTEM SET max_replication_slots = 10;
ALTER SYSTEM SET max_wal_senders = 10;
-- Reinicie o 12 para aplicar wal_level
-- Publicação (ajuste filtros conforme necessário)
CREATE PUBLICATION upgrade_pub FOR ALL TABLES;
-- No 14 (novo cluster)
-- Crie roles, extensions e estruturas antes da assinatura
CREATE SUBSCRIPTION upgrade_sub
CONNECTION 'host=old12 dbname=app user=replicator password=secret port=5432'
PUBLICATION upgrade_pub
WITH (copy_data = true, create_slot = true, slot_name = 'upgrade_slot');
Testes e validações antes do cutover
Execute o script de análise gerado pelo pg_upgrade (ou vacuumdb) para estatísticas adequadas. Compare cardinalidade de tabelas críticas, checksums de amostras e resultados de queries conhecidas. Rode cargas de leitura/gravação de baixa intensidade em staging conectado ao 14.
Valide migrations/DDL do app e planos de rollback de schema em Migrations e rollbacks em PostgreSQL: guia. Se notar regressão de plano ou estatísticas, veja técnicas em Como recuperar índices e stats no PostgreSQL.
- Rodar analyze/vacuum para planos estáveis.
- Comparar contagens por tabela e somatórios críticos.
- Reexecutar relatórios pesados e consultas de cache.
- Testar pooler e reconexão do app.
- Conferir permissões, roles e search_path.
# Após pg_upgrade, execute o script gerado
./analyze_new_cluster.sh
# Alternativa: analisar tudo com paralelismo
vacuumdb --all --analyze-in-stages --jobs=4
# Migrar objetos globais (roles, tablespaces)
pg_dumpall --globals-only | psql -h new14 -U postgres
Cutover controlado e janela de rollback
Organize um corte reversível. Bloqueie writes do app por curto período para eliminar divergência durante o teste de fumaça. Drene sessões antigas, aponte o endpoint para o 14 e monitore latência, locks e erros. Mantenha o 12 desligado, intacto e pronto para voltar.
Se você usa DNS, reduza TTL dias antes. Com HAProxy/PgBouncer, troque o backend e teste conexões novas primeiro. Documente o tempo e as migrações aplicadas.
- Bloqueio temporário de writes no app/role.
- Drenar sessões e encerrar conexões ativas.
- Flip de endpoint (DNS/HAProxy/PgBouncer).
- Smoke tests automatizados e manuais.
- Observação intensiva por um período acordado.
-- Exemplo: drenar sessões do banco 'app' (execute como superusuário)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'app' AND pid <> pg_backend_pid();
-- Opcional: tornar a role do app somente leitura durante o smoke
ALTER ROLE app SET default_transaction_read_only = on; -- reverter depois
Rollback seguro: critérios, execução e pós‑rollback
Defina critérios objetivos para reverter: corrupção detectada, regressão severa de performance, falhas críticas no app, ou incompatibilidade de extensões. O rollback precisa ser rápido e repetível.
Execução típica: pare o 14, aponte endpoints de volta ao 12, libere writes apenas após verificações básicas. Registre os writes perdidos no 14 (se houver) e avalie reconciliação manual.
Para reduzir perda de dados, você pode manter o app com writes bloqueados durante o smoke. Alternativamente, implemente replicação lógica reversa 14→12 antes do corte, ciente da complexidade e de conflitos. Como medida extrema, recorra a PITR; veja recuperação por point‑in‑time.
Este é exatamente o cenário em que vale preparar “como planejar e executar rollback seguro ao atualizar versão major do PostgreSQL 12→14 em produção com réplica de leitura”: critérios claros, passos ensaiados e comunicação contínua com as partes envolvidas.
- Critérios objetivos e aprovadores claros.
- Passos de reversão ensaiados e cronometrados.
- Comunicação ao negócio e registro de impacto.
- Plano de reconciliação de dados, se necessário.
- Checklist para reabrir o tráfego no 12.
Perguntas frequentes
Posso manter a réplica 12 seguindo o primário 14 após o upgrade?
Não. A replicação física é específica de versão. Clusters 12 e 14 não replicam entre si por streaming. Use side‑by‑side com pg_upgrade em cópia, ou replicação lógica (publicação/assinatura) para mover dados entre versões major diferentes.
Como minimizar downtime no corte para o 14?
Prepare tudo com antecedência: análise de estatísticas, roles e permissões migradas, teste em staging, TTL de DNS baixo, automação de flip via HAProxy/PgBouncer e bloqueio temporário de writes. Com replicação lógica, o 14 chega quase sincronizado e o corte é rápido.
É possível rollback sem perda de dados?
Possível, mas mais complexo. Você precisa bloquear writes durante o teste de fumaça ou configurar replicação lógica reversa 14→12 com estratégias de resolução de conflitos. Sem isso, voltar ao 12 implica descartar os writes feitos no 14 após o corte.
O que devo checar sobre extensões no upgrade 12→14?
Confirme se cada extensão usada possui versão compatível no 14 e plano de migração. Atualize extensões no momento certo e valide funções, tipos e índices associados. Em caso de dúvidas, isole o schema da extensão em testes antes de cortar o tráfego.
Preciso rodar VACUUM/ANALYZE após o upgrade?
Sim. Estatísticas atualizadas são vitais para bons planos de consulta. Rode o script gerado pelo pg_upgrade ou vacuumdb --analyze‑in‑stages. Após o corte, monitore consultas críticas e ajuste custos, índices e parâmetros se notar regressão.
Como tratar sequências na replicação lógica?
Sequências não são replicadas automaticamente. Inicialize valores manualmente no 14 após a cópia inicial ou sincronize usando scripts. Garanta que não haja sobreposição de valores e valide chaves antes de liberar writes no novo cluster.
Quer revisar seu plano de upgrade e rollback?
Se você precisa de uma segunda opinião no desenho do corte, validações e plano de retorno, vamos conversar sobre seu contexto e restrições.
Conversar sobre o upgradeVeja também
- Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados
- Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção
- Guia prático para dimensionamento de VPS e tuning de PHP‑FPM para lojas Magento/OpenMage com picos sazonais: do sizing ao teste de carga
- guia prático: reconstruir índices no PostgreSQL em produção usando CREATE INDEX CONCURRENTLY e índices parciais (passo a passo seguro)