Point-in-time recovery: restaurando para um momento específico

1. Fundamentos do Point-in-time Recovery (PITR)

Point-in-time recovery (PITR) é uma técnica de recuperação de bancos de dados que permite restaurar o sistema para um estado consistente em qualquer instante específico do passado. Diferente de um backup completo tradicional, que restaura apenas o estado do banco no momento em que o backup foi feito, o PITR possibilita "voltar no tempo" para um ponto exato entre backups.

A base do PITR está na combinação de dois elementos: um backup completo (full backup) e uma sequência contínua de logs de transações (WAL — Write-Ahead Log). Enquanto o backup completo fornece uma imagem base do banco, os logs registram todas as mudanças subsequentes, permitindo que o sistema seja reconstruído até qualquer ponto intermediário.

Os casos de uso mais comuns incluem:
- Erro humano: um usuário executa DELETE sem cláusula WHERE e percebe minutos depois
- Corrupção lógica: uma migração de schema mal-sucedida introduz inconsistências
- Rollback de migração: necessidade de retornar ao estado anterior a uma atualização de versão

2. Arquitetura por Trás do PITR

O coração do PITR é o Write-Ahead Log (WAL). No PostgreSQL, por exemplo, toda modificação no banco é primeiro registrada no WAL antes de ser aplicada aos arquivos de dados. Isso garante durabilidade e possibilita a reconstrução temporal.

Cada entrada no WAL possui um Log Sequence Number (LSN) — um identificador único e crescente que indica a posição exata do registro no log. Além do LSN, cada transação é associada a um timestamp e a um XID (Transaction ID), permitindo múltiplas formas de especificar o ponto de recuperação.

A arquitetura do PITR segue esta dependência:

Backup completo (base) + WALs sequenciais = Banco em qualquer ponto T

Se um WAL intermediário estiver faltante, a recuperação para pontos posteriores a ele se torna impossível. Por isso, a continuidade dos logs é crítica.

3. Estratégias de Backup para Viabilizar o PITR

Para habilitar o PITR, é necessário configurar o banco para arquivar os WALs continuamente. No PostgreSQL, isso envolve:

# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'cp %p /var/lib/pgsql/archive/%f'

A estratégia típica de backup para PITR é:

  1. Backup completo inicial (base backup) — usando pg_basebackup ou ferramentas como pgBackRest
  2. Backups incrementais/diferenciais — capturam apenas blocos alterados desde o último backup completo
  3. Arquivamento contínuo de WAL — cada segmento de WAL (geralmente 16 MB) é copiado para um diretório de archive

Políticas de retenção devem equilibrar espaço em disco versus necessidade de recuperação. Uma prática comum é manter WALs dos últimos 7 a 30 dias, combinados com backups completos semanais.

Exemplo de backup completo com pg_basebackup:

pg_basebackup -D /backup/base_20250325 -Ft -z -P -X stream

4. Executando a Restauração Point-in-time

O processo de restauração PITR no PostgreSQL segue estes passos:

Passo 1: Parar o servidor

pg_ctl stop -D /var/lib/pgsql/15/data

Passo 2: Restaurar o backup completo

rm -rf /var/lib/pgsql/15/data/*
tar -xzf /backup/base_20250325/base.tar.gz -C /var/lib/pgsql/15/data

Passo 3: Configurar o recovery target

Crie o arquivo recovery.signal no diretório de dados e configure postgresql.conf (ou recovery.conf em versões antigas):

# postgresql.conf (ou recovery.conf no PostgreSQL < 12)
restore_command = 'cp /var/lib/pgsql/archive/%f %p'
recovery_target_time = '2025-03-25 14:30:00 BRT'
recovery_target_action = 'promote'

Passo 4: Iniciar o servidor em modo recovery

pg_ctl start -D /var/lib/pgsql/15/data

O PostgreSQL aplicará automaticamente os WALs até o timestamp especificado e, em seguida, promoverá o banco para leitura/escrita.

Especificando o target

O target pode ser definido de várias formas:

recovery_target_time = '2025-03-25 14:30:00'  -- timestamp
recovery_target_xid = '1234567'                 -- transaction ID
recovery_target_lsn = '0/1A2B3C4D'              -- LSN
recovery_target_name = 'before_migration'       -- nome de restore point

5. Tratamento de Cenários Complexos no PITR

Recuperação até o último WAL disponível

Se você não especificar um target, o PostgreSQL aplicará todos os WALs disponíveis, recuperando até o último registro possível:

recovery_target_time = ''  -- ou omitir a diretiva

WALs corrompidos ou faltantes

Se um WAL necessário estiver faltante, a recuperação para após o último WAL íntegro. Para mitigar esse risco:

  • Configure archive_timeout para forçar o arquivamento frequente (ex.: a cada 60 segundos)
  • Use ferramentas como pg_waldump para inspecionar segmentos suspeitos:
pg_waldump /var/lib/pgsql/archive/00000001000000000000001A

PITR em ambientes replicados

Em replicação streaming, o standby mantém seus próprios WALs. Para fazer PITR em um standby:

  1. Promova o standby a primário (se necessário)
  2. Faça o backup do standby promovido
  3. Configure recovery_target no novo servidor

Em replicação cascata (standby de standby), a complexidade aumenta pois os WALs podem chegar com atraso. Nesses casos, é recomendável usar um repositório centralizado de WALs.

6. Validação e Boas Práticas Pós-Restauração

Após a restauração, valide a integridade dos dados:

# Verificar consistência do banco
pg_checksums -c /var/lib/pgsql/15/data

# Inspecionar transações recentes com pg_waldump
pg_waldump --start=0/1A2B3C00 --end=0/1A2B3DFF /var/lib/pgsql/archive/

Boas práticas essenciais:

  • Teste periodicamente: execute restaurações PITR em ambiente de staging a cada mês
  • Documente o processo: inclua comandos exatos e tempos esperados
  • Monitore o archive: verifique se os WALs estão sendo copiados corretamente:
SELECT * FROM pg_stat_archiver;
  • Mantenha backups completos regulares: o PITR depende de um base backup íntegro

7. Comparação com Ferramentas e Abordagens Alternativas

PITR nativo vs. Snapshot de disco (LVM/ZFS)

Característica PITR nativo Snapshot (LVM/ZFS)
Granularidade temporal Segundo a segundo Instantâneo fixo
Espaço em disco Alto (WALs contínuos) Baixo (copy-on-write)
Velocidade de recovery Lenta (replay de WALs) Rápida (montagem do snapshot)
Dependência de ferramenta Nenhuma (nativo) Sistema de arquivos

PITR vs. Replicação lógica contínua

A replicação lógica (como pglogical ou Decoding) permite manter um banco standby sincronizado quase em tempo real, mas não substitui o PITR:

  • PITR: recupera qualquer ponto no tempo, mesmo antes da replicação existir
  • Replicação lógica: mantém um clone atualizado, mas não permite "voltar" no histórico

Limitações do PITR

  • Dependência de WAL contínuo: se um WAL for perdido, a recuperação para além dele é impossível
  • Latência de recovery: bancos muito grandes ou com muitas transações podem levar horas para aplicar todos os WALs
  • Espaço em disco: manter meses de WALs requer planejamento de armazenamento

Referências