Imagine um serviço de carrinho de compras replicado em dois data centers. Uma falha de rede interrompe a comunicação entre eles, mas os usuários continuam enviando requisições para os dois lados.

Quando alguém adiciona um produto ao carrinho em um data center, o outro não consegue receber a atualização. O sistema precisa decidir: aceita novas operações mesmo sem confirmar o estado mais recente ou recusa parte delas até que a comunicação volte?

O teorema CAP ajuda a raciocinar sobre essa decisão.

O que é o teorema CAP?

O teorema CAP descreve um limite de sistemas distribuídos que armazenam dados em mais de um nó. As três letras representam:

  • C — Consistency: toda leitura recebe a escrita mais recente ou um erro;
  • A — Availability: toda requisição enviada a um nó operacional recebe uma resposta, sem garantia de que ela contenha o dado mais recente;
  • P — Partition tolerance: o sistema continua operando mesmo quando mensagens entre grupos de nós são perdidas ou atrasadas indefinidamente.

Nesse contexto, consistência significa uma visão única e atualizada do dado, próxima da garantia de linearizabilidade. Não é a mesma consistência da sigla ACID, que reúne propriedades de transações de banco de dados.

Disponibilidade também possui um sentido específico: cada requisição recebida por um nó que não falhou precisa terminar com uma resposta. Retornar erro porque o nó não consegue confirmar o valor mais recente preserva consistência, mas abre mão da disponibilidade definida pelo teorema.

O que acontece durante uma partição?

Considere duas réplicas que começam com o mesmo carrinho:

Réplica A                     Réplica B
carrinho = [livro]  ←──────→  carrinho = [livro]

Agora a conexão entre elas é interrompida:

Réplica A          ✕          Réplica B
carrinho = [livro]            carrinho = [livro]

Um usuário adiciona um teclado pela réplica A. Ao mesmo tempo, outra requisição consulta o carrinho pela réplica B. Como as réplicas não conseguem se comunicar, existem duas escolhas principais.

Priorizar consistência: comportamento CP

A réplica B recusa ou adia a leitura porque não consegue provar que possui o estado mais recente.

Escrita em A → [livro, teclado]
Leitura em B → erro ou espera

O sistema evita responder com um valor antigo, mas algumas operações ficam indisponíveis durante a partição.

Priorizar disponibilidade: comportamento AP

A réplica B responde imediatamente com o estado que conhece.

Escrita em A → [livro, teclado]
Leitura em B → [livro]

Todas as requisições recebem resposta, mas usuários podem observar dados desatualizados ou divergentes. Depois que a rede volta, o sistema precisa reconciliar as versões.

Por que “escolha dois de três” é uma simplificação ruim?

É comum resumir CAP como:

Escolha duas propriedades entre consistência, disponibilidade e tolerância a partições.

Essa frase sugere que as três propriedades são opções equivalentes e permanentes. Na prática, uma partição de rede não é uma configuração que o sistema simplesmente desativa. Se os dados estão distribuídos e a comunicação pode falhar, a arquitetura precisa definir como se comportará quando isso acontecer.

Sem partição, o sistema pode oferecer consistência e disponibilidade ao mesmo tempo. O trade-off aparece durante a partição:

Rede funcionando → consistência + disponibilidade podem coexistir
Rede particionada → priorizar consistência ou disponibilidade

Por isso, uma formulação mais útil é:

CP e AP na prática

As classificações CP e AP descrevem o comportamento do sistema diante de uma partição. Elas não dizem que todo recurso de um produto precisa fazer a mesma escolha.

PrioridadeDurante a partiçãoConsequênciaExemplos de requisito
CPRecusa operações sem confirmação suficienteParte do sistema pode ficar indisponívelEleição de líder, lock distribuído, saldo crítico
APAceita operações nos lados isoladosRéplicas podem divergir e exigir reconciliaçãoFeed, curtidas, posts em redes sociais e métricas aproximadas

Esses exemplos não determinam automaticamente a escolha. Um saldo, por exemplo, pode usar reservas, limites locais ou um ledger com regras específicas. O requisito de negócio é que define quais estados incorretos são aceitáveis e como corrigi-los.

Também não é preciso classificar um banco inteiro com uma única letra. Bancos modernos podem oferecer níveis de consistência, quóruns e políticas diferentes por operação. Uma leitura pode priorizar baixa latência, enquanto uma escrita crítica exige confirmação da maioria das réplicas.

Exemplo prático: um carrinho em duas regiões

Suponha que uma loja execute o serviço de carrinho em São Paulo e Virgínia. Cada região possui uma réplica e atende os usuários mais próximos.

Os requisitos são:

  • Adicionar um item deve continuar funcionando durante uma falha regional de comunicação;
  • Ver um item antigo por alguns segundos é aceitável;
  • Nenhuma alteração pode desaparecer silenciosamente;
  • As réplicas devem convergir quando a rede voltar.

Esses requisitos favorecem disponibilidade durante a partição:

São Paulo                          Virgínia
adiciona: teclado                  remove: livro
versão A               ✕           versão B
       \                               /
        └── rede volta e reconcilia ──┘

Responder às requisições é apenas metade da solução. O sistema também precisa registrar versões ou operações suficientes para reconciliar os estados. Algumas estratégias possíveis são:

  • Resolver conflitos com uma regra determinística;
  • Manter as duas versões para uma decisão posterior;
  • Modelar operações que possam ser combinadas;
  • Pedir ao usuário que confirme um conflito que não pode ser resolvido automaticamente.

Usar apenas “a última escrita vence” pode apagar uma alteração válida. Essa regra depende da qualidade dos relógios e, mesmo com timestamps corretos, escolhe uma versão sem entender a intenção do usuário.

Agora considere a confirmação do pagamento. Cobrar duas vezes ou confirmar uma compra sem uma reserva válida possui um custo muito maior. Esse fluxo pode exigir consistência mais forte e recusar a operação quando não houver quórum suficiente.

Carrinho → prioriza disponibilidade e reconcilia depois
Pagamento → prioriza consistência e pode rejeitar durante a falha

O mesmo produto pode, portanto, tomar decisões diferentes para operações diferentes.

Quórum e o trade-off

Em sistemas replicados, uma operação pode exigir respostas de parte das réplicas antes de ser considerada concluída.

Considere:

N = número de réplicas
W = confirmações exigidas para uma escrita
R = réplicas consultadas em uma leitura

Quando R + W > N, os conjuntos de leitura e escrita se sobrepõem. Isso ajuda uma leitura a encontrar uma versão recente, desde que o sistema compare versões corretamente. Aumentar R ou W, porém, também aumenta latência e reduz a chance de concluir a operação quando réplicas estão inacessíveis.

Quórum não elimina CAP. Ele é uma forma de escolher, por operação, quantas falhas podem ser toleradas e qual garantia de consistência será buscada.

Quando priorizar cada lado?

Considere priorizar consistência quando responder com um estado divergente puder:

  • Violar uma regra crítica de negócio;
  • Autorizar uma operação indevida;
  • Produzir uma decisão difícil ou impossível de compensar;
  • Quebrar exclusividade, como dois líderes ativos ou o mesmo recurso reservado duas vezes.

Considere priorizar disponibilidade quando:

  • Uma resposta aproximada ou temporariamente antiga ainda for útil;
  • Operações puderem ser reconciliadas ou compensadas;
  • Interromper o serviço causar mais dano que uma divergência temporária;
  • A experiência exigir aceitar trabalho offline ou entre regiões isoladas.

Antes de escolher, pergunte:

  1. Qual é o pior resultado de responder com dado antigo?
  2. Qual é o custo de rejeitar a operação?
  3. Conflitos podem ser detectados e reconciliados?
  4. A decisão vale para toda a aplicação ou apenas para esta operação?
  5. Quanto tempo de divergência o negócio aceita?

Vantagens e limitações do modelo CAP

O que CAP ajuda a enxergar

  • Torna explícito que falhas de comunicação afetam garantias do sistema;
  • Ajuda a discutir o comportamento esperado durante uma partição;
  • Separa requisitos de consistência dos de disponibilidade;
  • Expõe decisões que ficariam escondidas atrás da escolha de um banco de dados.

O que CAP não decide

  • A latência normal de leituras e escritas;
  • Quanto tempo as réplicas levam para convergir;
  • Como detectar e resolver conflitos;
  • Quais níveis de consistência existem fora de uma partição;
  • Como o sistema lida com perda de dados, falha de disco ou bugs;
  • Qual tecnologia deve ser usada.

CAP é um modelo para um cenário específico de falha, não um projeto completo de arquitetura.

Erros comuns

Dizer que um sistema “escolheu CA”

Em uma única máquina, uma partição entre réplicas não se aplica, mas também não existe tolerância a esse tipo de falha. Em um sistema realmente distribuído, a arquitetura ainda precisa definir o comportamento quando a comunicação quebra. Chamar o sistema de CA costuma esconder essa condição.

Confundir consistência CAP com consistência ACID

CAP trata da visão observada por operações distribuídas. ACID trata de propriedades de transações, como atomicidade, isolamento e durabilidade. Os conceitos podem se relacionar, mas não são intercambiáveis.

Achar que AP significa ausência de consistência

Um sistema AP pode oferecer consistência eventual, leituras monotônicas, resolução de conflitos e outras garantias. Ele apenas não promete que toda resposta durante uma partição refletirá a escrita mais recente.

Classificar uma tecnologia sem considerar a configuração

Topologia, fator de replicação, quórum, nível de consistência e tipo de operação mudam as garantias observadas. Dizer que um produto é sempre CP ou AP pode ser menos útil do que descrever sua configuração e seu comportamento em uma falha concreta.

Ignorar a reconciliação

Aceitar escritas nos dois lados de uma partição cria trabalho futuro. Sem versões, regras de merge, operações comutativas ou intervenção explícita, a disponibilidade apenas adia o problema.

Usar CAP para justificar qualquer trade-off

Nem todo conflito entre consistência e latência é causado por uma partição. CAP não substitui a análise de isolamento de transações, cache, replicação assíncrona, durabilidade ou desempenho.

Perguntas de entrevista

  1. Por que “escolha dois de três” não explica corretamente o teorema CAP?
  2. O que disponibilidade significa na definição de CAP?
  3. Como um sistema CP e um sistema AP se comportam durante a mesma partição?
  4. Por que um sistema AP ainda precisa de uma estratégia de reconciliação?
  5. Como quóruns de leitura e escrita afetam consistência, latência e disponibilidade?
  6. Um mesmo produto pode adotar decisões CP e AP? Dê um exemplo por operação.
  7. Qual é a diferença entre consistência no CAP e consistência no ACID?

Próximos conteúdos

Para continuar, estude replicação, consistência eventual, quóruns e consensus. Esses temas mostram como as réplicas propagam alterações, quais garantias uma aplicação pode oferecer e como nós distribuídos chegam a uma decisão comum mesmo diante de falhas.