Replicação streaming do PostgreSQL

    Replicação streaming mantém uma cópia exata do banco em tempo real em outro servidor — cada transação confirmada no primário é replicada para o standby em milissegundos. Serve tanto para alta disponibilidade (failover em caso de falha) quanto para distribuir leitura entre servidores.

    Configurar o servidor primário

    No servidor que será o primário (onde ocorrem as escritas):

    bash
    # /etc/postgresql/17/main/postgresql.conf (primário)
    wal_level = replica
    max_wal_senders = 3              # número máximo de standbys
    wal_keep_size = 256MB            # manter WAL para os standbys
    listen_addresses = '*'
    
    # Habilitar replicação por slot (não perde WAL mesmo com lag):
    # max_replication_slots = 3      # opcional, mais seguro
    
    # /etc/postgresql/17/main/pg_hba.conf (primário)
    # Adicionar: permitir o usuário de replicação do servidor standby
    host    replication     replicador      IP_STANDBY/32    scram-sha-256
    
    # Reiniciar primário
    sudo systemctl restart postgresql
    
    # Criar usuário de replicação
    sudo -u postgres psql
    CREATE ROLE replicador WITH REPLICATION LOGIN PASSWORD 'senha_replicacao';
    \q

    Inicializar o servidor standby com pg_basebackup

    No servidor standby — criar uma cópia base do primário:

    bash
    # No servidor standby — parar PostgreSQL se estiver rodando
    sudo systemctl stop postgresql
    
    # Limpar diretório de dados do standby
    sudo rm -rf /var/lib/postgresql/17/main/*
    
    # Cópia base do primário (rodada como postgres)
    sudo -u postgres pg_basebackup \
      --host=IP_PRIMARIO \
      --username=replicador \
      --pgdata=/var/lib/postgresql/17/main \
      --wal-method=stream \
      --checkpoint=fast \
      --progress \
      --verbose
    
    # Criar arquivo de configuração de standby
    sudo -u postgres cat > /var/lib/postgresql/17/main/postgresql.auto.conf << 'EOF'
    primary_conninfo = 'host=IP_PRIMARIO port=5432 user=replicador password=senha_replicacao'
    recovery_target_timeline = 'latest'
    EOF
    
    # Criar arquivo de sinal de standby (PostgreSQL 12+)
    sudo -u postgres touch /var/lib/postgresql/17/main/standby.signal
    
    # Iniciar standby
    sudo systemctl start postgresql
    
    # Verificar se está em modo standby:
    sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
    # t = standby (recuperação), f = primário

    Monitorar o lag de replicação

    Verifique que o standby está sincronizando corretamente:

    sql
    -- No primário — ver status dos standbys conectados:
    SELECT client_addr,
           state,
           sent_lsn,
           write_lsn,
           flush_lsn,
           replay_lsn,
           write_lag,
           flush_lag,
           replay_lag,
           sync_state
    FROM pg_stat_replication;
    
    -- No standby — verificar lag em relação ao primário:
    SELECT now() - pg_last_xact_replay_timestamp() AS lag_tempo,
           pg_is_in_recovery() AS em_standby,
           pg_last_wal_receive_lsn() AS recebido_ate,
           pg_last_wal_replay_lsn() AS aplicado_ate;
    
    -- Verificar diferença em bytes:
    -- No primário:
    SELECT pg_current_wal_lsn();
    -- No standby:
    SELECT pg_last_wal_replay_lsn();
    -- Diferença: SELECT 'a'::pg_lsn - 'b'::pg_lsn;

    Failover manual para o standby

    Em caso de falha do primário, promova o standby:

    bash
    # === Failover Manual ===
    
    # 1. Verificar que o primário está realmente indisponível
    pg_isready -h IP_PRIMARIO -p 5432
    # Se retornar erro, prosseguir com failover
    
    # 2. No servidor standby — promover para primário
    sudo -u postgres pg_ctl promote -D /var/lib/postgresql/17/main
    # Ou:
    sudo -u postgres psql -c "SELECT pg_promote();"
    
    # 3. Verificar que o standby foi promovido
    sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
    # f = agora é primário
    
    # 4. Atualizar a aplicação para apontar para o novo primário
    # (altere variável DATABASE_URL ou DNS)
    
    # 5. Quando o primário antigo voltar:
    # - Reinicializá-lo como standby do novo primário
    # - Repetir o processo de pg_basebackup a partir do novo primário
    Atenção
    Antes de promover o standby, confirme que o primário está realmente indisponível — promover com o primário ainda ativo causa split-brain (dois primários com dados divergentes).

    Replicação lógica para migração sem downtime

    A replicação lógica replica apenas tabelas selecionadas — útil para migrações e upgrades de versão:

    sql
    -- === Replicação Lógica (para migração de versão major) ===
    
    -- No primário (PostgreSQL 16):
    ALTER SYSTEM SET wal_level = 'logical';
    SELECT pg_reload_conf();
    
    -- Criar publicação de todas as tabelas:
    CREATE PUBLICATION migracao_pub FOR ALL TABLES;
    
    -- No novo servidor (PostgreSQL 17):
    -- Após copiar o schema (pg_dump --schema-only):
    CREATE SUBSCRIPTION migracao_sub
      CONNECTION 'host=IP_PRIMARIO port=5432 user=replicador
                  password=senha_replicacao dbname=minha_db'
      PUBLICATION migracao_pub;
    
    -- Monitorar progresso da sincronização inicial:
    SELECT subname, pid, relid::regclass AS tabela, state, received_lsn
    FROM pg_stat_subscription_stats;
    
    -- Quando sincronizado (state = 'ready' para todas as tabelas):
    -- 1. Parar a aplicação (janela de manutenção mínima)
    -- 2. Confirmar que o lag zerou
    -- 3. Apontar a aplicação para o novo servidor
    -- 4. Remover a subscription

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes