Replicação
Cópias do banco para leitura e para tolerar falhas, e o atraso entre a principal e as réplicas.
O problema: um banco só é um ponto único de falha
Com um único servidor de banco, uma falha de disco, uma atualização do sistema operacional ou uma zona da nuvem fora do ar param o sistema inteiro. E todas as leituras, inclusive os relatórios pesados, disputam a mesma máquina com as gravações.
A replicação mantém cópias do banco em outras máquinas. Um servidor é o principal (primary), que recebe as gravações; os outros são réplicas, que recebem as alterações do principal. As réplicas servem para duas coisas:
- Tolerar falhas: se o principal cair, uma réplica é promovida e passa a ser o novo principal.
- Atender leituras: consultas que não precisam do dado mais recente vão para as réplicas.
O tópico do teorema CAP mostra o efeito mais visível da replicação: a janela em que a réplica ainda não tem a última gravação. Este tópico trata da mecânica, das escolhas e do que dá errado. Os testes usaram o PostgreSQL 18, com um principal e uma réplica.
Como a réplica acompanha o principal
Todo banco relacional grava cada alteração primeiro num log sequencial, o WAL (write-ahead log) no PostgreSQL, para se recuperar de quedas. A replicação reaproveita esse log: o principal envia o WAL às réplicas em fluxo contínuo, e cada réplica o aplica, na mesma ordem.
Cada posição no log tem um número crescente, o LSN (log sequence number). O principal sabe até onde gravou; cada réplica sabe até onde recebeu e até onde aplicou. A diferença é o atraso de replicação, visível em pg_stat_replication.
Síncrona ou assíncrona
A pergunta central é quando o principal confirma a gravação para a aplicação:
| Modo | O principal confirma quando | Se o principal cair logo depois |
|---|---|---|
| Assíncrono (padrão) | Gravou no próprio disco | A gravação pode não ter chegado à réplica |
Síncrono (synchronous_commit = on) | A réplica também gravou no disco | A réplica tem a gravação |
Síncrono com aplicação (remote_apply) | A réplica gravou e aplicou | A réplica tem a gravação, e uma leitura nela já a vê |
O preço do síncrono é uma ida e volta até a réplica em cada COMMIT. Medimos com 5 ms de atraso de rede em cada sentido, gravando 200 linhas, cada uma confirmada sozinha:
synchronous_commit | Tempo por COMMIT |
|---|---|
local (assíncrono para a réplica) | 6,5 ms |
on | 18,3 ms |
remote_apply | 18,6 ms |
O tempo do assíncrono é quase só a ida e volta entre a aplicação e o principal. O síncrono somou a ida e volta até a réplica e a gravação no disco dela. Com a réplica em outra região, a centenas de quilômetros, cada COMMIT pagaria dezenas de milissegundos a mais.
O que se perde no assíncrono
Desconectamos a réplica da rede, gravamos 1.000 pedidos no principal, todos confirmados à aplicação, derrubamos o principal e promovemos a réplica:
| Pedidos | |
|---|---|
| Antes de desconectar a réplica | 602 |
| No principal, depois das gravações | 1.602 |
| Na réplica promovida | 602 |
As 1.000 gravações confirmadas sumiram. Para a aplicação, elas aconteceram: o cliente recebeu a confirmação do pedido. No novo principal, elas nunca existiram. Na prática, a réplica raramente fica tanto tempo desconectada, mas a janela é a mesma em escala menor: tudo o que o principal confirmou e ainda não tinha enviado no instante da queda se perde na troca.
O que trava no síncrono
O síncrono protege contra essa perda, e cobra de outro jeito. Com a réplica síncrona desconectada, um INSERT simples:
| Momento | Resultado |
|---|---|
Depois de 5 segundos, com statement_timeout = 2s | Ainda esperando a réplica |
| A linha, vista por outra sessão no principal | Não aparece |
Ao cancelar a espera (pg_cancel_backend) | A aplicação recebe sucesso |
Três surpresas. O statement_timeout não interrompeu a espera pela réplica: as gravações ficaram paradas sem limite, enquanto a réplica estava fora. A linha, já gravada no disco do principal, ficou invisível para as outras sessões até a espera terminar. E, ao cancelar a espera, a aplicação recebeu confirmação, e não erro. O PostgreSQL só registrou um aviso no log: "The transaction has already committed locally, but might not have been replicated to the standby". A aplicação acha que a gravação está protegida, e ela está só no principal.
Por isso, quem usa replicação síncrona costuma ter duas ou mais réplicas e exigir a confirmação de qualquer uma delas (synchronous_standby_names = 'ANY 1 (r1, r2)'): uma réplica fora não trava as gravações.
O slot que enche o disco
Para não apagar o WAL que uma réplica ainda não recebeu, o principal usa slots de replicação: cada réplica tem um slot, e o principal guarda o WAL até ela confirmar. Se a réplica for desligada e o slot esquecido, o principal guarda o WAL para sempre.
Criamos um slot que nenhuma réplica usava e gravamos cerca de 1,5 GB de alterações:
| Espaço do WAL no principal | |
|---|---|
| Antes | 48 MB |
| Depois das gravações, com o slot abandonado | 2.544 MB, todos retidos pelo slot |
Com max_slot_wal_keep_size = 256MB | 912 MB, e o slot marcado como perdido (lost) |
Sem limite, o disco do principal enche até o banco parar. Com o limite, o principal se protege e descarta o slot; a réplica ligada a ele precisa ser recriada do zero. As duas saídas são melhores que a terceira: monitorar os slots e apagar os que não têm réplica.
Por que isso importa quando a IA escreve o código
Um assistente que configura réplicas e roteia as leituras costuma tratar a réplica como um espelho instantâneo:
- Todas as leituras indo para a réplica, inclusive as que vêm logo depois de uma gravação.
- Decisões de negócio (saldo, estoque, permissão) tomadas com dado lido da réplica.
- Replicação assíncrona sem saber quanto pode ser perdido numa troca de principal.
- Uma única réplica síncrona, que trava o sistema quando cai.
- Slots de replicação sem monitoramento nem limite.
- Promoção manual da réplica sem impedir que o principal antigo volte e aceite gravações (dois principais ao mesmo tempo).
O próximo nível compara as topologias de replicação e as formas de rotear leituras e trocar de principal.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
Replicação em cinco minutos
Explique em no máximo cinco minutos de leitura o que é replicação de banco de dados, para alguém que só usou um banco num servidor. Cubra só o essencial: principal e réplicas, o log de alterações, replicação síncrona e assíncrona, o que se perde numa troca de principal e por que ler da réplica pode trazer dado velho. Use o exemplo de uma loja online com PostgreSQL. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
Síncrona, assíncrona e o que se perde
Quero entender a fundo a diferença entre replicação síncrona e assíncrona. Aja como um mentor e vá por etapas, esperando a minha resposta em cada uma: 1. O que o principal espera antes de confirmar o COMMIT em cada modo (local, remote_write, on, remote_apply). 2. Uma linha do tempo de uma troca de principal no modo assíncrono, e o que se perde. 3. O que acontece com as gravações quando a única réplica síncrona cai. 4. Replicação síncrona com quórum e por que ela resolve o problema anterior. 5. Como escolher o modo por transação. Em cada etapa, me dê um cenário e peça que eu diga o resultado.
Trocar de principal sem dois principais
Quero entender como uma réplica assume o lugar do principal. Explique: 1. A promoção de uma réplica e o que muda nela. 2. A detecção automática de falha e por que ela precisa de consenso. 3. O cérebro dividido: como dois principais acontecem e o estrago que causam. 4. Como a aplicação encontra o principal novo. 5. O que fazer com o principal antigo quando ele volta. Depois me descreva duas falhas e pergunte como a troca deveria acontecer em cada uma.
Ler da réplica sem mostrar dado velho
Quero entender as formas de ler das réplicas sem confundir o usuário. Explique: 1. Por que o usuário pode não ver o que acabou de gravar. 2. Ler sempre do principal depois de gravar, por um tempo. 3. Ler o que gravou com o LSN, e por que o LSN precisa ser lido depois do COMMIT. 4. Replicação com remote_apply. 5. Que leituras nunca devem ir para a réplica. Depois me dê quatro telas de um sistema e pergunte de onde cada uma deveria ler.