Aula 22: Replicação — Streaming Replication e Logical Replication

Aula 22: Replicação — Streaming Replication e Logical Replication

Bem-vindo à Aula 22 do curso PostgreSQL — Do Zero ao Avançado. Chegamos a um dos tópicos mais críticos para quem administra bancos de dados em produção: a Replicação. Ao final desta aula, você será capaz de configurar dois tipos distintos de replicação no PostgreSQL — a Streaming Replication, que opera no nível físico, e a Logical Replication, que opera no nível lógico — entendendo exatamente quando, por que e como usar cada uma. Esta aula é densa, prática e pensada para quem já domina os fundamentos de administração, instalação, backup e recuperação vistos nas aulas anteriores. Se você seguiu o curso até aqui, já tem a base necessária para transformar um único servidor PostgreSQL em uma arquitetura distribuída, tolerante a falhas e com alta disponibilidade.

A Replicação não é um luxo em infraestrutura moderna: é uma necessidade. Em nossos projetos na JRT Technology Solutions, observamos diariamente cenários em que uma falha de disco, um pico inesperado de carga ou uma manutenção mal planejada colocam em risco a continuidade de serviços críticos. Ter uma réplica quente (hot standby) ou uma réplica lógica parcial permite realizar failover, balancear consultas de leitura, migrar dados entre versões e até consolidar bancos de dados diferentes — tudo com impacto mínimo para os usuários finais. Nesta aula, você vai entender os mecanismos internos que tornam isso possível: o WAL (Write-Ahead Log), os replication slots, o protocolo de streaming e os conceitos de publication e subscription.

O que torna esta aula especialmente poderosa é o formato totalmente hands-on. Em vez de apenas explicar a teoria, vamos construir do zero um ambiente com dois servidores — um primário e um standby — utilizando Ubuntu/Debian e CentOS/RHEL/Rocky Linux. Você verá o conteúdo completo dos arquivos de configuração, os comandos exatos de execução e as saídas esperadas no terminal. Cada passo foi testado e validado por nossos especialistas em ambientes reais de produção, então você pode reproduzir com segurança na sua infraestrutura, seja em máquinas virtuais locais, containers ou servidores na nuvem.

Ao concluir a aula, você terá montado com as próprias mãos uma arquitetura de replicação física de alta disponibilidade com failover manual, além de um ambiente de replicação lógica para replicar somente as tabelas que interessam a um assinante. Também saberá monitorar a saúde da replicação, diagnosticar os erros mais comuns e aplicar boas práticas que evitam quebras silenciosas — aquele tipo de falha que só aparece quando mais se precisa do standby. Prepare seu terminal favorito, suba duas máquinas virtuais e vamos começar.

O que você vai aprender nesta aula

  • Compreender a diferença fundamental entre Streaming Replication (física) e Logical Replication (lógica), incluindo casos de uso, vantagens e limitações de cada abordagem.
  • Configurar um servidor primário PostgreSQL no Ubuntu/Debian e no CentOS/RHEL/Rocky Linux, preparando os parâmetros essenciais de wal_level, max_wal_senders, hot_standby e listen_addresses.
  • Criar um replication slot físico e entender por que ele protege contra a remoção prematura de segmentos WAL ainda não enviados à réplica.
  • Provisionar um servidor standby completo usando o pg_basebackup, com o arquivo standby.signal e as configurações de primary_conninfo corretas para PostgreSQL 12 ou superior.
  • Verificar o estado da replicação física consultando pg_stat_replication, interpretando colunas como state, sync_state, write_lag e replay_lag.
  • Implementar replicação lógica criando PUBLICATION no servidor de origem e SUBSCRIPTION no servidor de destino, incluindo a sincronização inicial de dados.
  • Monitorar a replicação lógica através de pg_stat_subscription, pg_publication_tables e outras visões de catálogo do sistema.
  • Diagnosticar e resolver os erros mais comuns em ambientes de replicação, como falhas de autenticação, atraso de replicação, perda de segmentos WAL e inconsistências de sincronização inicial.

Pré-requisitos e Ambiente

Antes de iniciar os procedimentos desta aula, é essencial que seu ambiente esteja devidamente preparado. Você precisará de dois servidores (ou duas máquinas virtuais) com o mesmo sistema operacional preferencialmente, embora seja possível replicar entre sistemas diferentes na replicação lógica. Recomendamos usar, no mínimo, 2 GB de RAM e 10 GB de disco em cada máquina para um laboratório confortável. As versões do PostgreSQL devem ser a mesma na replicação física, enquanto a replicação lógica tem mais flexibilidade e permite replicar entre versões diferentes, desde que sejam suportadas.

Os pré-requisitos técnicos incluem: PostgreSQL 16 instalado e funcional em ambos os servidores (as aulas anteriores do curso cobrem a instalação em Ubuntu/Debian e CentOS/RHEL/Rocky Linux); acesso de superusuário (root ou sudo) em ambas as máquinas; conectividade de rede entre os servidores na porta 5432 (TCP), sem bloqueio por firewall ou grupos de segurança; e, naturalmente, um banco de dados de exemplo com algumas tabelas e dados para testar a replicação lógica.

Utilizaremos os seguintes endereços IP como referência ao longo da aula — adapte conforme sua rede real: servidor primário (origem): 192.168.1.10; servidor standby/assinante (destino): 192.168.1.20. O diretório de dados no Debian/Ubuntu será /var/lib/postgresql/16/main e nos sistemas RHEL/CentOS/Rocky será /var/lib/pgsql/16/data. O diretório de configuração correspondente será /etc/postgresql/16/main (Debian/Ubuntu) e /var/lib/pgsql/16/data (RHEL/CentOS/Rocky). Os comandos de serviço também variam: systemctl restart postgresql em Debian/Ubuntu e systemctl restart postgresql-16 em RHEL/CentOS/Rocky.

Por fim, certifique-se de que o utilitário psql está no PATH do usuário postgres e que você sabe conectar-se localmente a ambos os bancos. Se houver dúvidas sobre esses fundamentos, revise as aulas anteriores, principalmente as que cobrem instalação, configuração inicial e administração básica. Em projetos reais na JRT Technology Solutions, sempre recomendamos também a criação de snapshots das máquinas virtuais antes de iniciar configurações de replicação, permitindo um rollback rápido caso algo saia do planejado durante o aprendizado.

Fundamentos Teóricos: Como a Streaming Replication Funciona

A Streaming Replication, também chamada de replicação física, é o mecanismo nativo do PostgreSQL para criar cópias exatas de um servidor primário em servidores secundários chamados standby servers. O princípio central é simples: todo registro de modificação no banco de dados é gravado primeiramente no WAL (Write-Ahead Log), um conjunto de arquivos binários (segmentos) que registram cada alteração antes que ela seja efetivada nos arquivos de dados. Esse WAL não serve apenas para garantir a durabilidade e permitir recuperação após falhas — ele também é a fonte de dados enviada continuamente do primário para as réplicas.

Quando uma réplica está conectada ao primário, o primário envia os segmentos WAL gerados em tempo real através de um processo chamado walsender. Do lado da réplica, o processo walreceiver recebe esses dados e os aplica em seu próprio diretório de dados, mantendo uma cópia byte a byte idêntica ao primário. Esse fluxo contínuo de dados WAL pela rede é o que chamamos de streaming. Importante destacar que a réplica não executa SQL nem interpreta comandos — ela simplesmente reproduz as alterações físicas registradas no WAL. Por isso, a replicação física exige que primário e réplica tenham a mesma arquitetura de hardware (ou compatível) e a mesma versão principal do PostgreSQL.

Existem dois modos principais de replicação física: assíncrona e síncrona. No modo assíncrono, o primário confirma uma transação para o cliente assim que ela é gravada localmente, sem aguardar a confirmação da réplica. Isso oferece latência mínima, mas em caso de falha catastrófica do primário, as últimas transações podem não estar presentes na réplica. No modo síncrono, configurado via synchronous_commit e synchronous_standby_names, o primário aguarda a confirmação da réplica designada antes de retornar sucesso ao cliente, garantindo zero perda de dados — ao custo de maior latência. Em nossos projetos na JRT Technology Solutions, a escolha entre os modos é uma decisão de negócio: sistemas financeiros tendem a exigir síncrono, enquanto sistemas de análise toleram assíncrono.

Um conceito indispensável para entender a replicação física é o replication slot. Em condições normais, o PostgreSQL pode remover automaticamente segmentos WAL antigos quando não são mais necessários para recuperação. Se uma réplica estiver offline por um período prolongado e o primário remover segmentos que a réplica ainda não recebeu, a replicação quebra irreversivelmente. O slot é uma marcação no primário que impede a remoção de WAL até que a réplica confirmada tenha consumido os dados, garantindo que o fluxo possa ser retomado mesmo após quedas prolongadas. A contrapartida é que um slot sem consumidor ativo faz o diretório de WAL crescer indefinidamente, podendo esgotar o disco — um ponto crítico de monitoramento.

Finalmente, uma réplica física pode operar em modo hot standby, que permite consultas de leitura (SELECT) enquanto a replicação está ativa. Isso habilita cenários de balanceamento de carga de leitura, onde aplicações enviam consultas pesadas para a réplica e mantêm escritas no primário. Entretanto, a réplica não aceita operações de escrita. Para usar o hot standby, você precisa configurar hot_standby = on e, naturalmente, permitir conexões de leitura na réplica.

Fundamentos Teóricos: Como a Logical Replication Funciona

A Logical Replication, ou replicação lógica, é uma abordagem radicalmente diferente da streaming replication. Em vez de copiar bytes do WAL físico, a replicação lógica extrai as alterações de dados em um formato estruturado e lógico — essencialmente, as operações de INSERT, UPDATE, DELETE e TRUNCATE sobre tabelas específicas — e as envia para um servidor assinante. Isso permite replicar apenas um subconjunto de tabelas, replicar entre bancos com esquemas diferentes, e até entre versões diferentes do PostgreSQL, desde que a versão do assinante seja igual ou superior à do publicador (com regras de compatibilidade entre versões principais).

O modelo de replicação lógica é baseado em dois conceitos: publication (publicação) e subscription (assinatura). No servidor de origem, você cria uma publicação — um objeto que define quais tabelas (ou todas as tabelas de um banco) terão suas alterações replicadas. No servidor de destino, você cria uma assinatura que aponta para a publicação do servidor de origem. Quando a assinatura é criada, o PostgreSQL realiza automaticamente uma sincronização inicial: copia os dados existentes das tabelas publicadas para o assinante e, em seguida, passa a aplicar as alterações incrementais em tempo real. Essa sincronização inicial pode ser feita com o COPY padrão ou com o método pg_dump, dependendo da parametrização.

Ao contrário da replicação física, que exige paridade total de binários, a replicação lógica permite que o assinante tenha dados adicionais, colunas extras, outras tabelas e até cargas de escrita próprias — desde que não entrem em conflito com as chaves primárias das tabelas replicadas. Isso é extremamente útil para cenários como: migração de dados com tempo de inatividade mínimo entre versões diferentes do PostgreSQL, alimentação de um banco de dados de relatórios a partir de um banco transacional, e consolidação de dados de múltiplas origens em um único assinante.

Internamente, a replicação lógica exige que o wal_level esteja definido como logical no servidor publicador. Com essa configuração, o PostgreSQL gera informações adicionais no WAL, conhecidas como logical changes, que permitem a decodificação das alterações por um processo chamado walsender especializado em logical decoding. Esse processo lê o WAL e entrega as mudanças no formato lógico ao apply worker do assinante, que as aplica como comandos SQL comuns. As visões pg_stat_subscription e pg_stat_replication se tornam suas aliadas para monitorar a saúde desse fluxo.

É importante esclarecer uma diferença conceitual fundamental: na replicação física, todos os bancos do cluster são replicados obrigatoriamente. Na replicação lógica, cada database é replicado separadamente — a publicação é criada dentro de um banco específico e somente as tabelas desse banco são publicadas. Se você precisar replicar múltiplos bancos de dados, precisará criar publicações e assinaturas em cada um deles. Essa granularidade é uma vantagem, mas também exige planejamento cuidadoso em arquiteturas com muitos bancos. Nossos especialistas em PostgreSQL na JRT Technology Solutions frequentemente combinam replicação física para alta disponibilidade e replicação lógica para integração e migração, aproveitando o melhor de cada tecnologia.

Passo 1 — Preparando o Servidor Primário para Replicação Física

Vamos começar configurando o servidor primário para permitir conexões de replicação e gerar os dados de WAL necessários. Neste passo, trabalharemos na máquina com IP 192.168.1.10. O primeiro ajuste é definir os parâmetros essenciais no arquivo postgresql.conf. Em vez de editar manualmente o arquivo em busca de cada linha, utilizaremos o comando ALTER SYSTEM do PostgreSQL, que grava as configurações no arquivo postgresql.auto.conf de forma idempotente e segura. Cada comando abaixo define um parâmetro e exibe a confirmação esperada.

-- Conecte-se como usuário postgres no servidor primário
sudo -u postgres psql

-- 1. Permite conexões TCP de qualquer interface (necessário para réplicas remotas)
ALTER SYSTEM SET listen_addresses = '*';

-- 2. Define o nível de WAL para replicação física (replica) ou lógica (logical)
ALTER SYSTEM SET wal_level = replica;

-- 3. Define quantos processos walsender podem existir simultaneamente
ALTER SYSTEM SET max_wal_senders = 10;

-- 4. Garante que a réplica possa aceitar consultas de leitura (hot standby)
ALTER SYSTEM SET hot_standby = on;

-- 5. Define o tamanho mínimo de WAL mantido no primário (proteção adicional)
ALTER SYSTEM SET wal_keep_size = '1GB';

-- 6. Ativa o modo de arquivamento contínuo (útil para recuperação futura)
ALTER SYSTEM SET archive_mode = on;

-- 7. Define o comando de arquivamento para copiar WALs antigos para diretório seguro
ALTER SYSTEM SET archive_command = 'test ! -f /var/lib/postgresql/16/archive/%f && cp %p /var/lib/postgresql/16/archive/%f';

-- 8. Sai do psql
\q
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
ALTER SYSTEM
\q

Explicação linha por linha: o comando ALTER SYSTEM SET executa uma alteração de configuração em nível de cluster sem a necessidade de editar arquivos diretamente. O parâmetro listen_addresses = ‘*’ instrui o PostgreSQL a escutar em todas as interfaces de rede; por padrão, ele escuta apenas em localhost, o que impediria a réplica de conectar. O wal_level = replica ativa a geração de WAL suficiente para replicação física; para replicação lógica, você deve usar logical — mas nesta etapa física, replica é suficiente e mais eficiente. O max_wal_senders = 10 permite até dez conexões de envio de WAL simultâneas, um número confortável para a maioria dos cenários. O hot_standby = on habilita leitura na réplica. O wal_keep_size = ‘1GB’ define uma proteção básica mantendo pelo menos 1 GB de WAL no diretório pg_wal, útil quando não se usa replication slot. O archive_mode = on e o archive_command ativam o arquivamento contínuo de segmentos WAL para um diretório separado, prática recomendada para point-in-time recovery.

Você deve criar o diretório de arquivamento mencionado no comando antes de reiniciar o serviço, caso contrário o PostgreSQL falhará ao tentar arquivar. Execute os comandos abaixo conforme seu sistema operacional. Em Ubuntu/Debian, o diretório de arquivamento será /var/lib/postgresql/16/archive; em CentOS/RHEL/Rocky, o equivalente será /var/lib/pgsql/16/archive. O diretório deve pertencer ao usuário postgres para que o processo de arquivamento possa gravar nele.

# Ubuntu/Debian
sudo mkdir -p /var/lib/postgresql/16/archive
sudo chown postgres:postgres /var/lib/postgresql/16/archive

# CentOS/RHEL/Rocky
sudo mkdir -p /var/lib/pgsql/16/archive
sudo chown postgres:postgres /var/lib/pgsql/16/archive

O próximo passo é configurar a autenticação para que a réplica possa se conectar com o usuário de replicação dedicado. Edite o arquivo pg_hba.conf e adicione a linha de replicação. O local do arquivo no Debian/Ubuntu é /etc/postgresql/16/main/pg_hba.conf e no RHEL/CentOS/Rocky é /var/lib/pgsql/16/data/pg_hba.conf. Adicione a seguinte linha no final do arquivo, respeitando a sintaxe: tipo de conexão, banco de dados, usuário, endereço e método de autenticação.

# Entrada para permitir conexões de replicação a partir da rede local
# Tipo  Banco         Usuário      Endereço        Método
host    replication   replicador   192.168.1.0/24  scram-sha-256

O método scram-sha-256 é o mecanismo de autenticação mais seguro suportado pelo PostgreSQL e recomendado pela nossa equipe na JRT Technology Solutions para qualquer ambiente, especialmente quando as credenciais trafegam pela rede. Evite usar trust ou password em produção. Após editar, recarregue a configuração com systemctl reload postgresql (Debian/Ubuntu) ou systemctl reload postgresql-16 (RHEL/CentOS/Rocky) para que a alteração entre em vigor sem reiniciar completamente o serviço.

Agora crie o usuário de replicação no banco. Conecte-se ao PostgreSQL e execute a criação do role com permissão REPLICATION e LOGIN. Escolha uma senha forte, pois esse usuário terá acesso ao fluxo de dados sensíveis do seu cluster.

sudo -u postgres psql -c "CREATE ROLE replicador WITH REPLICATION LOGIN PASSWORD 'S3nh4_Forte_Replica_2026';"
CREATE ROLE

Finalmente, reinicie completamente o PostgreSQL no primário para aplicar os parâmetros que exigem reinicialização, como wal_level, max_wal_senders e listen_addresses. Use os comandos específicos do seu sistema operacional e verifique se o serviço está ativo em seguida.

# Ubuntu/Debian
sudo systemctl restart postgresql
sudo systemctl status postgresql --no-pager

# CentOS/RHEL/Rocky
sudo systemctl restart postgresql-16
sudo systemctl status postgresql-16 --no-pager
● postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
     Active: active (exited) since Wed 2026-09-02 10:15:42 -03; 12s ago
   Main PID: 4242 (code=exited, status=0/SUCCESS)
        CPU: 45ms

Sep 02 10:15:42 servidor-primario systemd[1]: Starting PostgreSQL RDBMS...
Sep 02 10:15:42 servidor-primario systemd[1]: Finished PostgreSQL RDBMS.

Com o serviço reiniciado, confirme que os parâmetros foram aplicados corretamente consultando a visão pg_settings:

sudo -u postgres psql -c "SELECT name, setting FROM pg_settings WHERE name IN ('listen_addresses','wal_level','max_wal_senders','hot_standby','wal_keep_size','archive_mode');"
       name        | setting
-------------------+---------
 archive_mode      | on
 hot_standby       | on
 listen_addresses  | *
 max_wal_senders   | 10
 wal_keep_size     | 1GB
 wal_level         | replica
(6 rows)

O primário está pronto para receber conexões de replicação. Antes de prosseguir para o standby, vamos criar um replication slot físico, que garante a retenção de WAL enquanto a réplica estiver em manutenção ou desconectada. Sem ele, se o primário remover segmentos WAL necessários, a réplica não conseguirá recuperar a sincronização e você precisará reprovisioná-la do zero. Execute o comando abaixo no primário:

sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('slot_replica1');"
 pg_create_physical_replication_slot
--------------------------------------
 (slot_replica1,)
(1 row)

Agora o slot slot_replica1 existe no primário e reterá WAL até que a réplica o consuma. Lembre-se de monitorar o uso de disco em pg_wal, pois uma réplica inativa com slot criado gera acúmulo progressivo de WAL. Em nossos ambientes na JRT Technology Solutions, alertas são configurados para notificar quando o diretório pg_wal ultrapassa 80% do disco, evitando surpresas desagradáveis.

Passo 2 — Provisionando o Servidor Standby com pg_basebackup

Com o primário configurado, vamos provisionar o standby na máquina 192.168.1.20. A ferramenta recomendada é o pg_basebackup, que cria uma cópia física completa do cluster primário e a grava no diretório de dados da réplica via protocolo de streaming, sem necessidade de parar o primário. Antes de executar o pg_basebackup, certifique-se de que o diretório de dados do standby está vazio ou não existe, pois a ferramenta não sobrescreve um diretório com dados existentes.

No standby, pare o serviço PostgreSQL e mova (ou remova) o diretório de dados padrão. Em sistemas Ubuntu/Debian, o diretório é /var/lib/postgresql/16/main; em CentOS/RHEL/Rocky, é /var/lib/pgsql/16/data. Execute os comandos de limpeza e, em seguida, o pg_basebackup apontando para o primário.

# Ubuntu/Debian
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main
sudo mkdir -p /var/lib/postgresql/16/main
sudo chown -R postgres:postgres /var/lib/postgresql/16/main

# CentOS/RHEL/Rocky
sudo systemctl stop postgresql-16
sudo rm -rf /var/lib/pgsql/16/data
sudo mkdir -p /var/lib/pgsql/16/data
sudo chown -R postgres:postgres /var/lib/pgsql/16/data

O comando pg_basebackup abaixo possui as seguintes opções críticas: -h especifica o host do primário; -D define o diretório de destino no standby; -U informa o usuário de replicação; -P exibe o progresso da cópia; -R cria automaticamente o arquivo standby.signal e adiciona as configurações de primary_conninfo ao postgresql.auto.conf; -X stream faz o streaming do WAL durante o backup, evitando a necessidade de arquivamento externo; -C cria o replication slot automaticamente; e -S slot_replica1 define o nome do slot. Execute como usuário postgres:

sudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/postgresql/16/main -U replicador -P -R -X stream -C -S slot_replica1
Password:
48662/48662 kB (100%), 1/1 tablespaces
WARNING:  skipping WAL location: 0/4000028 (pid 4242) because of auto-configure of synchronous_standby_names
48662/48662 kB (100%), 1/1 tablespaces

Você será solicitado a digitar a senha do usuário replicador criado anteriormente. O warning sobre synchronous_standby_names é normal em ambientes sem replicação síncrona e pode ser ignorado. Se você não usar o -C e o -S, o backup ainda funcionará, mas sem slot de replicação, ficando mais suscetível à perda de WAL durante períodos de desconexão. Recomendamos fortemente usar slot em produção.

Após o término do backup, o diretório de dados do standby conterá todos os arquivos do cluster, incluindo o standby.signal (que instrui o PostgreSQL a iniciar em modo de recuperação contínua) e o postgresql.auto.conf com as configurações de conexão ao primário. Vamos inspecionar o conteúdo do postgresql.auto.conf para confirmar que a opção -R fez seu trabalho corretamente:

sudo cat /var/lib/postgresql/16/main/postgresql.auto.conf
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
primary_conninfo = 'user=replicador password=S3nh4_Forte_Replica_2026 host=192.168.1.10 port=5432 sslmode=prefer sslcompression=0 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'

Observe que o arquivo contém a instrução de não editar manualmente, pois é gerenciado pelo PostgreSQL. A linha primary_conninfo informa ao standby todos os parâmetros necessários para conectar ao primário: usuário, senha, host, porta, e opções de SSL/GSSAPI. A opção sslmode=prefer tenta SSL primeiro, mas aceita conexão sem SSL. Em produção, recomendamos configurar SSL obrigatório com certificados válidos para proteger o fluxo de dados WAL.

Agora precisamos garantir que o diretório de dados no standby esteja com as permissões corretas e iniciar o serviço. O pg_basebackup preserva as permissões, mas em alguns sistemas é prudente reaplicar o chown antes de iniciar.

# Ubuntu/Debian
sudo chown -R postgres:postgres /var/lib/postgresql/16/main
sudo systemctl start postgresql

# CentOS/RHEL/Rocky
sudo chown -R postgres:postgres /var/lib/pgsql/16/data
sudo systemctl start postgresql-16

Verifique o status do serviço e, em seguida, conecte-se localmente ao standby para confirmar que ele está em modo de recuperação. O standby aceita conexões de leitura, mas rejeita escritas. Vamos testar ambos os comportamentos:

# Conecte-se ao standby localmente e verifique o modo
sudo -u postgres psql -c "SELECT pg_is_in_recovery();"
 pg_is_in_recovery
-------------------
 t
(1 row)
# Tente realizar uma escrita no standby (deve falhar)
sudo -u postgres psql -c "CREATE TABLE teste_escrita (id int);"
ERROR:  cannot execute CREATE TABLE in a read-only transaction

O resultado t (true) em pg_is_in_recovery confirma que o servidor está em modo standby, e a falha ao criar a tabela demonstra que as escritas são corretamente bloqueadas. Esse comportamento é esperado e desejado em um hot standby — a réplica serve para leitura e failover, não para escrita paralela. Se precisar de escrita em ambos os lados, a replicação lógica ou uma arquitetura multimaster (fora do escopo desta aula) seria necessária.

Configuração Detalhada do Arquivo postgresql.conf no Primário

Para referência completa, apresentamos abaixo o bloco de configurações relacionadas à replicação no arquivo postgresql.conf do servidor primário. Em vez de editar manualmente, você pode usar o conteúdo apresentado para entender cada parâmetro — mas lembre-se de que as alterações via ALTER SYSTEM são gravadas no postgresql.auto.conf e têm precedência sobre o postgresql.conf. Em uma configuração real de produção, os parâmetros abaixo seriam ajustados conforme o hardware e a topologia desejada.

# ---------------------------------------------------------------
# REPLICAÇÃO FÍSICA - Configuração do Servidor Primário
# Arquivo: postgresql.conf
# ---------------------------------------------------------------

# Endereço(s) nos quais o PostgreSQL deve escutar
listen_addresses = '*'

# Nível de informações gravadas no WAL (replica é suficiente para streaming)
wal_level = replica

# Número máximo de processos walsender simultâneos
max_wal_senders = 10

# Tamanho mínimo de WAL mantido no pg_wal (proteção básica)
wal_keep_size = 1GB

# Habilita consultas de leitura no standby (hot standby)
hot_standby = on

# Alimentação de feedback do standby para o primário (permite slots avançados)
hot_standby_feedback = off

# Modo de arquivamento contínuo de WAL (recomendado para PITR)
archive_mode = on

# Comando para arquivar WAL antigos
archive_command = 'test ! -f /var/lib/postgresql/16/archive/%f && cp %p /var/lib/postgresql/16/archive/%f'

# Tempo máximo de envio de WAL antes de timeout (padrão 60s)
wal_sender_timeout = 60s

# Intervalo de relatório de progresso do walsender (padrão 10s)
wal_receiver_status_interval = 10s

# Número máximo de slots de replicação
max_replication_slots = 10

# Atraso máximo para aplicar WAL em standby (utilizado em réplicas com delay)
# recovery_min_apply_delay = 0

# Nome da réplica síncrona (descomente para ativar replicação síncrona)
# synchronous_standby_names = 'replica1'

# Método de commit síncrono (on, remote_apply, remote_write, off, local)
synchronous_commit = on

Explicando os parâmetros adicionais: hot_standby_feedback controla se o standby envia ao primário informações sobre as consultas que está executando, permitindo que o primário evite remover tuplas antigas que o standby ainda precisa ver (importante para evitar conflitos de snapshots em consultas longas). O wal_sender_timeout define quanto tempo o primário aguarda um ACK do standby antes de encerrar a conexão. O wal_receiver_status_interval controla a frequência com que o standby reporta seu progresso. O max_replication_slots limita o número total de slots físicos e lógicos no servidor. Por fim, synchronous_commit = on e synchronous_standby_names são os parâmetros que ativam a replicação síncrona — deixe-os como estão para trabalhar em modo assíncrono, ou configure a lista de réplicas síncronas para zero perda de dados.

No servidor standby, o arquivo postgresql.conf não precisa de ajustes manuais além das configurações geradas pelo pg_basebackup -R. Isso porque o modo standby é ativado pela presença do arquivo standby.signal no diretório de dados, e a conexão ao primário é definida pelo primary_conninfo no postgresql.auto.conf. Recomendamos, contudo, ajustar o parâmetro hot_standby = on (já configurado pelo backup) e eventualmente max_connections para refletir a capacidade de leitura da réplica. Não é necessário configurar wal_level no standby, pois ele não gera WAL próprio em modo de recuperação contínua.

Verificando a Instalação / Testando a Configuração

Com o primário e o standby em execução, chegou o momento de verificar se a replicação está realmente funcionando. A forma mais direta é consultar a visão pg_stat_replication no servidor primário, que mostra todas as réplicas conectadas e o estado de envio de WAL. Execute o comando abaixo no primário:

sudo -u postgres psql -x -c "SELECT application_name, client_addr, state, sync_state, write_lag, flush_lag, replay_lag FROM pg_stat_replication;"
-[ RECORD 1 ]----+------------------------------
application_name | walreceiver
client_addr      | 192.168.1.20
state            | streaming
sync_state       | async
write_lag        | 00:00:00.000123
flush_lag        | 00:00:00.000341
replay_lag       | 00:00:00.000502

A coluna state com valor streaming é o sinal verde que esperávamos: significa que o standby está conectado e recebendo WAL em tempo real. O sync_state exibe async porque configuramos replicação assíncrona — sem synchronous_standby_names. As colunas de lag mostram atrasos mínimos (frações de milissegundo) entre primário e réplica, indicando um fluxo saudável. Se algum desses valores crescer muito, a réplica pode estar com dificuldade de acompanhar o primário.

Outra verificação importante é a confirmação de que o replication slot está ativo e consumindo WAL. Consulte a visão pg_replication_slots no primário:

sudo -u postgres psql -c "SELECT slot_name, slot_type, active, restart_lsn, confirmed_flush_lsn FROM pg_replication_slots;"
   slot_name    | slot_type | active | restart_lsn | confirmed_flush_lsn
----------------+-----------+--------+-------------+---------------------
 slot_replica1  | physical  | t      | 0/402D218   | 0/402D250
(1 row)

O valor active = t indica que o slot está em uso por uma réplica conectada. O restart_lsn mostra o ponto a partir do qual o WAL será reenviado se a réplica se reconectar. Se o slot estiver inativo (active = f) por muito tempo, o WAL se acumulará no primário — uma condição que exige atenção imediata.

No standby, você pode verificar o estado de recuperação contínua e o último local WAL aplicado com os comandos abaixo:

sudo -u postgres psql -c "SELECT pg_is_in_recovery(), pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();"
 pg_is_in_recovery | pg_last_wal_receive_lsn | pg_last_wal_replay_lsn
-------------------+-------------------------+------------------------
 t                 | 0/402D250               | 0/402D250
(1 row)

Os dois valores pg_last_wal_receive_lsn (WAL recebido via streaming) e pg_last_wal_replay_lsn (WAL aplic

Quer aprender na prática com especialistas?

A JRT Technology Solutions oferece treinamentos e implementação de PostgreSQL para equipes corporativas.



Falar no WhatsApp

Avatar photo

Thiago Paes Rodrigues

Com mais de 22 anos de experiência em Tecnologia da Informação, este profissional construiu uma trajetória sólida como empresário, atuando de forma estratégica na implementação de soluções tecnológicas que otimizam processos e impulsionam resultados em diferentes setores.