← Voltar ao blog
PostgreSQL 23 de setembro de 2026 11 min de leitura

Alta disponibilidade e replicação no PostgreSQL: o que ainda dói

Streaming replication é sólida, mas failover automático não vem na caixa. Slots, synchronous_commit, split-brain, Patroni e o pesadelo da latência em ambiente híbrido — com SQL e configuração real.

Alta disponibilidade e replicação no PostgreSQL: o que ainda dói

Tem uma frase que eu ouço em toda reunião de arquitetura: "a replicação do Postgres é muito boa". É verdade. O que ninguém completa é a segunda parte: replicação não é alta disponibilidade. Replicação é cópia de dados. Alta disponibilidade é alguém decidir, sozinho e rápido, qual nó manda agora — e isso o PostgreSQL deliberadamente não faz por você.

Servidor primário replicando para duas réplicas, com chaveamento de failover entre datacenter e nuvem
O desenho é simples. O que dói é a decisão automática de quem vira primário.

Os três sabores de replicação (e quando cada um serve)

TipoO que replicaServe paraLimitação
Física (streaming)Blocos de WAL, o cluster inteiroHA, DR, réplicas de leituraMesma versão major, réplica read-only, tudo ou nada
LógicaLinhas, por tabela ou publicaçãoUpgrade sem downtime, CDC, consolidaçãoNão replica DDL nem sequences por padrão
Backup contínuo (PITR)WAL arquivado mais base backupRecuperação a um ponto no tempoRTO alto; não é failover

Streaming replication: o mínimo que funciona

No primário, o essencial da configuração:

-- Verifique antes de mexer
SHOW wal_level;            -- precisa ser 'replica' (ou 'logical')
SHOW max_wal_senders;      -- pelo menos número de réplicas + 2
SHOW wal_keep_size;

-- Role dedicada para replicação (nunca use o superusuário da aplicação)
CREATE ROLE replicador WITH REPLICATION LOGIN PASSWORD 'troque-isto';

-- Slot de replicação: garante que o WAL não seja descartado
SELECT * FROM pg_create_physical_replication_slot('replica_sp1');

E a linha que separa quem dorme de quem não dorme:

-- Confirma commit só quando a réplica gravou o WAL
ALTER SYSTEM SET synchronous_commit = 'remote_write';
ALTER SYSTEM SET synchronous_standby_names = 'ANY 1 (replica_sp1, replica_rj1)';
SELECT pg_reload_conf();

O preço do síncrono

Cada COMMIT passa a esperar a rede. Em datacenter único com 0,3 ms de RTT, ninguém percebe. Em híbrido on-premise para cloud com 18 ms, cada COMMIT ganha 18 ms — e a sua aplicação que faz 40 commits por request acabou de ganhar 720 ms. Aqui a escolha vira negócio: quantos milissegundos de latência valem zero byte de perda de dados?

Meu padrão: ANY 1 com duas réplicas locais síncronas e a réplica remota assíncrona para DR. Você protege contra perda de dados sem amarrar o COMMIT à WAN.

O perigo silencioso dos slots órfãos

Slot de replicação garante que o WAL espera a réplica. Se a réplica morre e ninguém remove o slot, o primário acumula WAL até encher o disco e parar. Já vi isso derrubar produção em feriado mais de uma vez. Monitore:

SELECT slot_name, active,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS wal_retido
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC;

A partir do PostgreSQL 13 existe rede de segurança: max_slot_wal_keep_size. Configure. Sempre.

Failover automático: Patroni e o problema do split-brain

Patroni é o padrão de mercado. Ele usa um DCS (etcd, Consul ou Kubernetes) para eleição por consenso, e só o nó que segura a chave de líder aceita escrita. O trecho que importa:

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576   # 1 MB - acima disso, nao promove
    synchronous_mode: true
postgresql:
  parameters:
    synchronous_commit: remote_write
  pg_hba:
    - hostssl replication replicador 10.0.0.0/8 scram-sha-256

Três armadilhas que vejo direto:

  • DCS com dois nós. Consenso precisa de quórum ímpar. Dois nós não é cluster, é empate.
  • Sem fencing. Se o primário antigo volta e ainda tem VIP ou conexões apontando, você tem dois primários aceitando escrita. Isso é split-brain, e o estrago é irreversível.
  • Aplicação com IP fixo. Use HAProxy ou PgBouncer com health check no endpoint do Patroni, ou o failover só troca o problema de lugar.

O teste que quase ninguém faz

Backup não testado não é backup. Failover não ensaiado não é HA. Meu ritual trimestral, em janela controlada:

  1. Matar o processo do primário à força (não shutdown limpo — a vida real não é limpa).
  2. Cronometrar até a aplicação voltar a escrever. Esse número é o seu RTO real.
  3. Conferir se houve transação perdida comparando o último LSN replicado.
  4. Reintegrar o nó antigo com pg_rewind e medir quanto tempo levou.
pg_rewind --target-pgdata=/var/lib/postgresql/16/main \
          --source-server="host=novo-primario user=replicador dbname=postgres" \
          --progress

Réplica de leitura não é bala de prata

Mandar relatório para a réplica é ótimo, até a query de 40 minutos entrar em conflito com o replay do WAL. Aí você escolhe entre cancelar a query (max_standby_streaming_delay) ou atrasar a limpeza no primário (hot_standby_feedback = on, que devolve bloat — assunto do artigo sobre VACUUM e bloat).

Não existe configuração certa aqui, existe a escolha consciente. O erro é descobrir qual você fez durante o incidente.

Para o panorama completo das dores de operação, volte ao guia definitivo de PostgreSQL em produção. Se a sua topologia é MySQL, o raciocínio equivalente está em MySQL em aplicações críticas e escaláveis.


Sobre o autor: Alexandre Almeida atua com bancos de dados há mais de 25 anos, foi instrutor oficial de MySQL e Oracle para mais de 1.000 alunos e escreveu Aprendendo MySQL: Prática, Teoria e Laboratórios. Configurações validadas em PostgreSQL 16 e 17 com Patroni 4.

Fontes: PostgreSQL Documentation — High Availability, Load Balancing and Replication; Replication Slots; documentação oficial do Patroni; notas de release do PostgreSQL 13 a 17.