DevGuideTK
← Trilha Backend

Teorema CAP e consistência

A escolha obrigatória entre consistência e disponibilidade quando a rede se divide, e os níveis de consistência entre os dois extremos.

Mais de uma cópia do mesmo dado

Um único servidor de banco é simples: só existe uma versão de cada dado. Mas ele é um ponto único de falha e tem limite de capacidade. Por isso, os sistemas mantêm cópias:

  • réplicas de leitura, que recebem as alterações do banco principal e atendem consultas;
  • várias regiões, para atender usuários de perto e sobreviver à queda de um data center;
  • caches, que guardam cópias dos dados mais lidos.

A partir do momento em que existem cópias, surge uma pergunta que um servidor único não tinha: todas as cópias estão iguais agora? Copiar leva tempo, e a rede entre as máquinas pode falhar.

O teorema CAP

O teorema CAP descreve três propriedades de um sistema com dados replicados:

LetraPropriedadeO que significa
CConsistênciaToda leitura vê a escrita mais recente, como se existisse uma única cópia
ADisponibilidadeToda requisição a uma máquina que está funcionando recebe uma resposta, sem erro
PTolerância a partiçãoO sistema continua funcionando quando a rede entre as máquinas se divide

A forma popular, "escolha duas das três", engana. Em qualquer sistema com mais de uma máquina, a rede vai falhar em algum momento: um cabo, um roteador, uma zona de nuvem isolada. A tolerância a partição não é opcional.

O teorema, então, diz o seguinte: quando a rede se divide, o sistema precisa escolher entre consistência e disponibilidade.

A escolha na prática

Imagine dois data centers com cópias do saldo de uma conta, e a conexão entre eles cai. Um cliente, conectado ao data center A, tenta sacar. O data center A não consegue saber se o saldo mudou no data center B.

EscolhaO que o sistema fazConsequência
Consistência (CP)Recusa o saque, ou espera a rede voltarO cliente recebe um erro, mas o saldo nunca fica errado
Disponibilidade (AP)Aceita o saque com o saldo que conheceO cliente é atendido, mas os dois lados podem aceitar saques que, juntos, passam do saldo

Nenhuma das duas é errada em geral. Para um saldo bancário, a consistência costuma ser obrigatória. Para o contador de curtidas de uma publicação, mostrar um número um pouco velho é muito melhor do que mostrar um erro.

Mesmo sem falha: atraso e consistência

O CAP fala do momento da falha, que é raro. O que acontece o tempo todo é outra troca, descrita por uma extensão do teorema chamada PACELC: com partição (P), escolha entre disponibilidade (A) e consistência (C); senão (E, de else), escolha entre latência (L) e consistência (C).

Na operação normal, manter todas as cópias iguais exige esperar que cada escrita chegue às outras máquinas antes de confirmar. Isso custa tempo em toda escrita. Não esperar é rápido, mas deixa uma janela em que as cópias diferem.

Reproduzimos essa janela no PostgreSQL, com um banco principal e uma réplica de leitura, na configuração mais comum: replicação assíncrona. Com a aplicação das alterações pausada na réplica para simular um atraso:

escrita no principal:   UPDATE pedidos SET status = 'pago' WHERE id = 981
o principal lê:         pago
a réplica lê:           aberto      ← dado velho

Na operação normal, o atraso costuma ser de milissegundos. Sob carga, durante uma manutenção ou com a réplica longe, chega a segundos ou minutos. E qualquer leitura feita na réplica durante esse intervalo devolve o valor antigo.

Os níveis de consistência

Entre "todas as cópias sempre iguais" e "um dia elas ficam iguais" existem vários níveis. Os mais úteis no dia a dia:

NívelGarantiaExemplo do que evita
Forte (linearizável)Toda leitura vê a última escrita confirmada, de qualquer usuárioDois clientes comprando o último item, cada um vendo estoque 1
Ler as próprias escritasO usuário sempre vê o que ele mesmo salvouO endereço antigo depois de salvar o novo
Leituras monotônicasO usuário nunca vê um dado mais velho do que um que já viuUm comentário que aparece, some no próximo carregamento e volta
CausalSe B foi escrito por causa de A, quem vê B também vê AVer a resposta de um comentário sem ver o comentário original
EventualSem novas escritas, todas as cópias acabam iguaisNada no curto prazo; só garante a convergência

Um detalhe importante: muitos problemas reais são resolvidos com os níveis do meio, especialmente ler as próprias escritas, sem pagar o custo da consistência forte para todos os usuários.

Por que isso importa quando a IA escreve o código

Um assistente que configura réplicas de leitura ou um cache faz a parte da infraestrutura funcionar. Os efeitos de consistência ficam por conta de quem revisa:

  • Todas as leituras passam a ir para a réplica, inclusive a que vem logo depois de uma escrita.
  • Uma decisão de negócio, como aprovar um pedido ou conferir um saldo, é tomada com um dado lido da réplica.
  • A tela mostra um valor do cache que acabou de ser alterado.
  • O sistema é descrito como "consistente" sem que ninguém tenha definido o que isso significa para cada dado.

O próximo nível compara os sistemas pela escolha que fazem e mostra como decidir para cada tipo de dado.

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.

  • CAP em cinco minutos

    Explique em no máximo cinco minutos de leitura o teorema CAP e o que significa consistência em sistemas com mais de uma cópia dos dados, para alguém que programa mas nunca trabalhou com réplicas.
    
    Cubra só o essencial: por que existem cópias, o que acontece quando a rede entre elas falha, a escolha entre responder com dado velho ou recusar, e por que ler de uma réplica pode trazer um dado velho mesmo sem falha.
    
    Use o exemplo de um saldo bancário e de um contador de curtidas. No final, me faça três perguntas curtas para eu verificar se entendi, e corrija as minhas respostas.
  • O teorema CAP sem simplificações

    Quero entender o teorema CAP corretamente, sem a versão simplificada de "escolha duas de três".
    
    Aja como um mentor de sistemas distribuídos. Pergunte primeiro qual é a minha experiência.
    
    Conduza assim, uma etapa por vez:
    1. Defina com precisão consistência, disponibilidade e tolerância a partição, como o teorema usa esses termos.
    2. Explique por que a tolerância a partição não é opcional em sistemas com mais de uma máquina.
    3. Descreva uma partição entre dois data centers e pergunte o que eu faria com uma escrita num sistema de reservas de passagens, antes de explicar as duas escolhas.
    4. Explique a extensão PACELC e a troca entre latência e consistência na operação normal.
    5. Mostre por que dizer "o banco X é CP" é uma simplificação.
    
    Faça uma pergunta de verificação em cada etapa e espere a minha resposta antes de continuar.
  • Os níveis de consistência com exemplos

    Quero entender os níveis de consistência entre "forte" e "eventual", com exemplos concretos.
    
    Explique, um por vez, com um cenário de rede social ou de loja virtual em que cada um faz diferença:
    1. Consistência forte (linearizável).
    2. Ler as próprias escritas.
    3. Leituras monotônicas.
    4. Consistência causal.
    5. Consistência eventual.
    
    Para cada nível, descreva o que o usuário veria se o sistema não oferecesse aquela garantia.
    
    Depois me apresente seis situações e pergunte qual é o nível mínimo necessário em cada uma. Corrija as minhas respostas.
  • O que acontece numa réplica atrasada

    Quero entender o atraso de replicação na prática, com um banco relacional e uma réplica de leitura.
    
    Pergunte qual banco eu uso. Explique, para ele:
    1. Como a replicação funciona: o registro de alterações, o envio para a réplica e a aplicação na réplica.
    2. A diferença entre replicação síncrona e assíncrona, e o que cada uma garante em caso de queda do principal.
    3. O que causa atraso na réplica: carga, consultas longas na réplica, rede, manutenção.
    4. O sintoma típico na aplicação: o usuário salva e não vê o que salvou.
    5. Como medir o atraso.
    
    Se possível, me ajude a montar um principal e uma réplica com Docker para eu ver o atraso acontecer, pausando a aplicação das alterações na réplica.