Consistência eventual
Como projetar telas e regras de negócio quando a leitura pode vir desatualizada.
O problema: cópias que ainda não concordam
Quase todo sistema real guarda o mesmo dado em mais de um lugar: o banco principal e as réplicas, o banco e o cache, o serviço de pedidos e o de entregas, que recebe os eventos por uma fila. As cópias não mudam todas no mesmo instante. Por um tempo, uma delas tem o valor novo e outra ainda tem o antigo.
Consistência eventual é a garantia mínima nesse cenário: se as gravações pararem, todas as cópias acabam iguais. Ela não diz quando, nem o que cada leitura vê até lá. O tópico do teorema CAP apresenta essa troca e os níveis de consistência; o de replicação mostra a janela de atraso de uma réplica. Este tópico trata de como projetar telas e regras de negócio que convivem com essa janela.
O que o usuário não pode ver
A maior parte do atraso passa despercebida. Alguns efeitos, porém, quebram a confiança no sistema:
| Efeito | O que o usuário vê | Garantia que evita |
|---|---|---|
| Não ver o que acabou de gravar | Muda o endereço, a tela mostra o antigo | Ler o que gravou (read your writes) |
| O tempo voltar | O pedido aparece "enviado" e, ao recarregar, "pago" | Leituras monotônicas |
| Efeito antes da causa | Vê a resposta a um comentário que ainda não aparece | Consistência causal |
O segundo efeito foi reproduzido com um PostgreSQL 18, um principal e duas réplicas. A réplica B teve a aplicação do log pausada, e o status do pedido 981 mudou de pago para enviado no principal. Um balanceador que alterna as réplicas a cada pedido devolveu:
| Leituras seguidas do mesmo pedido | Status |
|---|---|
| Alternando entre as réplicas A e B | enviado, pago, enviado, pago, enviado, pago |
| Sempre na réplica A | enviado, enviado, enviado |
| Sempre na réplica B | pago, pago, pago |
| Na réplica B, depois de ela alcançar o principal | enviado |
Com o balanceador alternando, o pedido "voltou no tempo" a cada recarga, um efeito muito pior que um atraso fixo. Prendendo cada usuário a uma réplica, as leituras dele pararam de oscilar: podem estar atrasadas, mas nunca andam para trás. O "ler o que gravou", com o LSN da última gravação, foi medido no tópico de replicação.
Quando duas cópias mudam ao mesmo tempo
O atraso de leitura é o caso fácil. O difícil é quando duas cópias aceitam gravações ao mesmo tempo, sem se comunicar: dois servidores em regiões diferentes, dois dispositivos sem rede, duas instâncias que mesclam estados depois. Quando as cópias se encontram, alguém precisa decidir o resultado.
A regra mais comum é a última gravação vence (last write wins): cada gravação leva o horário de quem gravou, e a de horário maior fica. É simples e perde dados de dois jeitos:
- Gravações simultâneas se sobrescrevem: se duas pessoas somam ao mesmo contador, uma soma desaparece.
- Relógios divergem: o servidor com o relógio adiantado vence mesmo quando gravou antes.
Simulamos um contador em três nós, A, B e C, que somaram 5, 3 e 2 sem se comunicar, e depois trocaram os estados. O relógio do nó C estava adiantado:
| Forma | Valor final nos três nós (o certo é 10) |
|---|---|
| A última gravação vence | 2, o valor do nó com o relógio adiantado |
| Contador que converge (G-Counter) | 10, 10 e 10 |
Estruturas que convergem sozinhas
Um CRDT (conflict-free replicated data type) é uma estrutura de dados desenhada para que qualquer cópia possa mudar sozinha, e para que a mesclagem dê sempre o mesmo resultado. A mesclagem tem três propriedades:
| Propriedade | Significado | Por que importa |
|---|---|---|
| Comutativa | Mesclar A com B dá o mesmo que B com A | A ordem de chegada não importa |
| Associativa | (A com B) com C dá o mesmo que A com (B com C) | Os agrupamentos não importam |
| Idempotente | Mesclar o mesmo estado duas vezes não muda nada | Mensagens repetidas não estragam |
O contador do teste é o mais simples: cada nó guarda só quanto ele mesmo somou, e a mesclagem fica com o maior valor de cada nó. No teste, o nó A recebeu B e depois C; o nó C recebeu B e depois A; o nó B recebeu o estado de A duas vezes. Os três chegaram a 10, nas cinco linguagens.
Há CRDTs para conjuntos, registros, mapas, listas e textos. São a base de editores colaborativos e de aplicações que funcionam sem rede (Automerge, Yjs), e de bancos que aceitam gravações em várias regiões (Riak, Redis Enterprise com replicação ativa-ativa). O preço é que nem toda regra de negócio cabe num CRDT: "o saldo nunca fica negativo" exige coordenação.
Regras de negócio com dados atrasados
Algumas decisões aceitam um dado de alguns segundos atrás; outras não:
| Decisão | Pode ler uma cópia atrasada? |
|---|---|
| Mostrar a contagem de curtidas | Sim |
| Listar os pedidos do cliente | Sim, com "ler o que gravou" para o pedido recém-criado |
| Exibir o estoque na vitrine | Sim, como estimativa |
| Confirmar a compra do último item do estoque | Não: a reserva acontece na fonte da verdade, com gravação condicional |
| Liberar um saque pelo saldo | Não |
| Conferir se o usuário ainda tem permissão | Não, para ações sensíveis |
O padrão é separar mostrar de decidir: a tela pode mostrar a cópia rápida; a decisão que não admite erro acontece onde o dado é a fonte da verdade, com as proteções do tópico de níveis de isolamento.
Por que isso importa quando a IA escreve o código
Um assistente que acrescenta réplicas, cache ou eventos ao sistema costuma tratar todas as cópias como se fossem a fonte da verdade:
- Leituras distribuídas entre réplicas sem afinidade, com dados que oscilam a cada recarga.
- A tela recém-alterada lida de uma cópia atrasada.
- Decisões de saldo, estoque e permissão tomadas com dados de cache ou de réplica.
- "A última gravação vence" com o relógio de cada servidor, perdendo gravações simultâneas.
- Contadores replicados incrementados com ler, somar e gravar.
- Consumidores de eventos que não toleram mensagens repetidas ou fora de ordem.
O próximo nível compara as garantias de leitura, as formas de resolver conflitos e os padrões de tela para dados eventualmente consistentes.
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.
Consistência eventual em cinco minutos
Explique em no máximo cinco minutos de leitura o que é consistência eventual, para alguém que só trabalhou com um banco de dados sem réplicas nem cache. Cubra só o essencial: por que as cópias de um dado divergem por um tempo, o que o usuário não pode ver (não ver o que gravou, o tempo voltar), o problema de "a última gravação vence" e por que decisões importantes leem a fonte da verdade. Use o exemplo de uma loja com réplicas de leitura e cache. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
As garantias de leitura
Quero entender as garantias de leitura em sistemas eventualmente consistentes. Aja como um mentor e, para cada garantia (ler o que gravou, leituras monotônicas, consistência causal), uma de cada vez: 1. Mostre uma sequência de leituras que a viola, com réplicas em atrasos diferentes. 2. Peça que eu diga o que o usuário vê. 3. Explique como implementá-la (afinidade, LSN, versões) e o custo. Espere a minha resposta em cada etapa.
Conflitos de gravação e CRDTs
Quero entender o que acontece quando duas cópias aceitam gravações ao mesmo tempo. Explique: 1. Por que "a última gravação vence" perde dados, com gravações simultâneas e com relógios divergentes. 2. Detectar conflitos com versão e devolver ao usuário. 3. O que é um CRDT e as três propriedades da mesclagem. 4. G-Counter, PN-Counter e OR-Set, com exemplos. 5. Que regras de negócio não cabem num CRDT. Depois me descreva três dados de um aplicativo que funciona sem rede e pergunte como eu resolveria os conflitos de cada um.
Mostrar e decidir
Quero aprender a separar o que pode ler uma cópia atrasada do que precisa da fonte da verdade. Me descreva, uma de cada vez, oito situações de um sistema (vitrine, carrinho, pagamento, saldo, permissões, painel, notificações, relatórios) e pergunte se cada uma pode usar uma cópia atrasada. Depois de cada resposta, explique a resposta certa e o que pode dar errado.