A replicação streaming do PostgreSQL fornece um mecanismo robusto para manter cópias em tempo real do seu banco de dados em múltiplos servidores. Seja para alta disponibilidade, recuperação de desastres ou escalabilidade de leitura, a replicação streaming oferece consistência em nível de bytes com lag mínimo. Este guia conduz você pela configuração de uma arquitetura primário-standby do zero, configuração de arquivamento WAL, monitoramento da saúde da replicação e planejamento de estratégias de failover.

Pré-requisitos

  • Dois servidores Linux (Ubuntu 22.04+ ou RHEL 9+) com conectividade de rede
  • PostgreSQL 16 ou posterior instalado em ambos os servidores
  • Espaço em disco suficiente para arquivos WAL e backups base
  • Acesso root ou sudo em ambas as máquinas
  • Porta 5432 aberta entre os servidores primário e standby
  • Familiaridade básica com os arquivos de configuração do PostgreSQL

Entendendo a Replicação no PostgreSQL

O PostgreSQL suporta dois modos principais de replicação: replicação streaming e replicação lógica. A replicação streaming opera no nível de bytes WAL (Write-Ahead Log), enviando um fluxo contínuo de registros WAL do primário para os standbys. Isso cria uma cópia binária exata de todo o cluster.

O processo de replicação segue este fluxo:

  1. O primário grava as mudanças em segmentos WAL
  2. O processo WAL sender transmite os registros para os standbys conectados
  3. O WAL receiver do standby grava os registros no WAL local
  4. O processo startup do standby reproduz os registros WAL para atualizar os arquivos de dados

A replicação streaming pode operar em modo assíncrono (padrão) ou síncrono. O modo assíncrono oferece melhor desempenho com lag mínimo, enquanto o síncrono garante zero perda de dados ao custo de latência na escrita.

Configuração do Servidor Primário

Edite o arquivo postgresql.conf do servidor primário para habilitar a replicação:

# /etc/postgresql/16/main/postgresql.conf

listen_addresses = '*'
wal_level = replica
max_wal_senders = 5
wal_keep_size = '1GB'
hot_standby = on

O parâmetro wal_level = replica garante que o WAL contenha informação suficiente para replicação. max_wal_senders controla quantas conexões de streaming simultâneas são permitidas. wal_keep_size impede que o primário recicle segmentos WAL antes que o standby os tenha consumido.

Em seguida, configure pg_hba.conf para permitir que o standby se conecte para replicação:

# /etc/postgresql/16/main/pg_hba.conf

# TYPE  DATABASE        USER            ADDRESS              METHOD
host    replication     replicator      10.0.1.20/32         scram-sha-256

Substitua 10.0.1.20 pelo endereço IP do seu servidor standby.

Crie um usuário dedicado para replicação:

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'your_secure_password';

Reinicie o PostgreSQL para aplicar as mudanças de configuração:

sudo systemctl restart postgresql

Configuração do Servidor Standby

No servidor standby, pare o PostgreSQL e limpe o diretório de dados existente:

sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main/*

Execute pg_basebackup para clonar os dados do primário:

sudo -u postgres pg_basebackup \
  -h 10.0.1.10 \
  -U replicator \
  -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R

As flags têm propósitos específicos:

  • -Fp: Formato de saída plano
  • -Xs: Transmite WAL durante o backup para evitar lacunas
  • -P: Mostra o progresso
  • -R: Cria automaticamente standby.signal e grava primary_conninfo em postgresql.auto.conf

Se preferir configuração manual, crie o sinal de standby e as configurações de conexão você mesmo:

touch /var/lib/postgresql/16/main/standby.signal

Adicione ao postgresql.conf no standby:

primary_conninfo = 'host=10.0.1.10 port=5432 user=replicator password=your_secure_password application_name=standby1'
hot_standby = on

Inicie o servidor standby:

sudo systemctl start postgresql

Arquivamento WAL

O arquivamento WAL fornece uma rede de segurança adicional ao copiar segmentos WAL completos para um local de arquivo. Isso permite recuperação point-in-time (PITR) e protege contra cenários onde o standby fica muito atrasado.

Configure o arquivamento no primário:

# /etc/postgresql/16/main/postgresql.conf

archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'

Crie o diretório de arquivo:

sudo mkdir -p /var/lib/postgresql/wal_archive
sudo chown postgres:postgres /var/lib/postgresql/wal_archive

Para ambientes de produção, use rsync ou uma solução de armazenamento em nuvem em vez de cp local:

archive_command = 'rsync -a %p backup-server:/wal_archive/%f'

Configure o standby para usar WAL arquivado como fallback com restore_command:

# No postgresql.conf do standby
restore_command = 'cp /mnt/wal_archive/%f %p'

Isso permite que o standby recupere segmentos WAL do arquivo quando o streaming fica atrasado.

Monitoramento do Lag de Replicação

Monitorar o lag de replicação é crítico para garantir que seu standby permaneça atualizado. No servidor primário, consulte pg_stat_replication:

SELECT
  client_addr,
  application_name,
  state,
  sent_lsn,
  write_lsn,
  flush_lsn,
  replay_lsn,
  pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes,
  write_lag,
  flush_lag,
  replay_lag
FROM pg_stat_replication;

No servidor standby, verifique o status do receptor e calcule o lag:

SELECT
  status,
  received_lsn,
  latest_end_lsn,
  last_msg_send_time,
  last_msg_receipt_time
FROM pg_stat_wal_receiver;

-- Estimativa de lag baseada em tempo
SELECT
  now() - pg_last_xact_replay_timestamp() AS replication_delay;

Configure um alerta quando o lag exceder seu limite:

#!/bin/bash
LAG_BYTES=$(psql -h primary -U monitor -t -c \
  "SELECT pg_wal_lsn_diff(sent_lsn, replay_lsn) FROM pg_stat_replication WHERE application_name='standby1';")

if [ "$LAG_BYTES" -gt 104857600 ]; then
  echo "ALERTA: Lag de replicação excede 100MB ($LAG_BYTES bytes)" | mail -s "PG Replication Alert" admin@example.com
fi

Estratégias de Failover

Quando o primário falha, você precisa de um plano claro de failover. O PostgreSQL fornece vários métodos de promoção:

Promoção manual:

# Usando pg_ctl
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main

# Usando SQL (PostgreSQL 12+)
SELECT pg_promote(wait := true, wait_seconds := 60);

Promoção por arquivo trigger:

Configure promote_trigger_file no postgresql.conf do standby:

promote_trigger_file = '/tmp/postgresql.trigger'

Crie o arquivo para acionar a promoção:

touch /tmp/postgresql.trigger

Failover automatizado com Patroni:

Para ambientes de produção, use uma ferramenta como Patroni com etcd:

# /etc/patroni/patroni.yml (trecho)
scope: pg-cluster
namespace: /db/
name: node1

restapi:
  listen: 0.0.0.0:8008

etcd:
  hosts: 10.0.1.100:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    maximum_lag_on_failover: 1048576

postgresql:
  listen: 0.0.0.0:5432
  data_dir: /var/lib/postgresql/16/main
  authentication:
    replication:
      username: replicator
      password: your_secure_password

Após o failover, o antigo primário deve ser reintroduzido como standby usando pg_rewind:

sudo -u postgres pg_rewind \
  --target-pgdata=/var/lib/postgresql/16/main \
  --source-server="host=10.0.1.20 port=5432 user=postgres"

Comparação: Streaming vs Replicação Lógica

CaracterísticaReplicação StreamingReplicação Lógica
Nível de replicaçãoNível de bytes (WAL)Nível de linha (mudanças decodificadas)
Escopo do clusterCluster completoPor tabela ou por banco de dados
Suporte entre versõesRequer mesma versão maiorSuporta versões maiores diferentes
Escrita no standbySomente leitura (hot standby)Leitura-escrita no subscriber
Replicação de DDLAutomáticaManual (não replicada)
Overhead de desempenhoMuito baixoModerado (custo de decodificação)
Complexidade de configuraçãoSimplesModerada
Caso de usoHA e recuperação de desastresReplicação seletiva e migrações

Escolha replicação streaming para alta disponibilidade do cluster completo. Escolha replicação lógica quando precisar de replicação seletiva de tabelas, atualizações entre versões ou subscribers com escrita.

Cenário Real

Você gerencia um banco de dados de produção de e-commerce que processa 5.000 transações por segundo. O negócio requer menos de 30 segundos de inatividade durante qualquer falha. Veja como arquitetar a solução:

O servidor primário (10.0.1.10) processa todas as escritas. O standby síncrono (10.0.1.20) no mesmo datacenter garante zero perda de dados. O standby assíncrono (10.0.2.10) em um datacenter remoto fornece recuperação de desastres.

Configure a replicação síncrona no primário:

synchronous_standby_names = 'FIRST 1 (standby_dc1, standby_dc2)'
synchronous_commit = on

Direcione as consultas de leitura para os standbys usando PgBouncer ou HAProxy:

# /etc/haproxy/haproxy.cfg (trecho)
listen pg-read
    bind *:5433
    mode tcp
    balance roundrobin
    option pgsql-check user haproxy
    server standby1 10.0.1.20:5432 check
    server standby2 10.0.2.10:5432 check

Essa arquitetura fornece zero perda de dados para falhas locais e perda mínima para eventos em nível de datacenter, enquanto descarrega o tráfego de leitura para os standbys.

Armadilhas e Casos Especiais

  • Remoção de segmentos WAL: Se o standby desconectar por mais tempo do que wal_keep_size permite, ele não consegue se atualizar via streaming. Sempre configure arquivamento WAL como rede de segurança ou use slots de replicação: SELECT pg_create_physical_replication_slot('standby1_slot');
  • Slots de replicação e uso de disco: Slots de replicação não utilizados impedem a limpeza de WAL, potencialmente enchendo o disco. Monitore pg_replication_slots e remova slots inativos
  • Transações grandes: Uma única transação massiva (importação em massa) gera enormes volumes de WAL que podem sobrecarregar o standby ou a rede. Divida operações grandes em lotes
  • Latência de commit síncrono: Habilitar synchronous_commit = on com standbys síncronos adiciona o tempo de ida e volta da rede a cada commit. Teste o throughput de escrita antes de habilitar
  • Divergência de timeline: Após promover um standby, o antigo primário está em um timeline diferente. Você deve usar pg_rewind ou reconstruí-lo completamente antes de reintroduzi-lo como standby
  • Senha em primary_conninfo: Armazene credenciais em .pgpass em vez de texto plano nos arquivos de configuração

Solução de Problemas

Standby não conecta:

# Verificar logs do standby
sudo tail -f /var/log/postgresql/postgresql-16-main.log

# Verificar conexões de replicação no primário
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"

# Testar conectividade a partir do standby
psql -h 10.0.1.10 -U replicator -d postgres -c "IDENTIFY_SYSTEM;"

Lag de replicação crescendo:

-- Verificar se o standby está reproduzindo
SELECT pg_is_in_recovery(), pg_last_wal_replay_lsn();

-- Verificar consultas de longa duração bloqueando a reprodução
SELECT pid, query, state, wait_event FROM pg_stat_activity
WHERE state != 'idle' AND backend_type = 'client backend';

Arquivo WAL enchendo:

# Verificar status do arquivamento
sudo -u postgres psql -c "SELECT * FROM pg_stat_archiver;"

# Limpar arquivos antigos manualmente (manter pelo menos 1 dia)
find /var/lib/postgresql/wal_archive -mtime +1 -delete

Resumo

  • A replicação streaming do PostgreSQL cria cópias binárias em tempo real de todo o seu cluster de banco de dados
  • Configure wal_level = replica, max_wal_senders e um usuário de replicação no primário
  • Use pg_basebackup com a flag -R para inicializar standbys com configuração automática
  • O arquivamento WAL fornece uma rede de segurança para standbys que ficam atrasados no streaming
  • Monitore o lag de replicação via pg_stat_replication e pg_stat_wal_receiver
  • Use Patroni ou ferramentas similares para failover automatizado em produção
  • Slots de replicação impedem a remoção de WAL mas requerem monitoramento para evitar esgotamento de disco
  • Sempre teste seu procedimento de failover antes de precisar dele em uma emergência

Artigos Relacionados