Duas bilheterias e o telefone que caiu
Duas bilheterias vendem os mesmos ingressos e se ligam a cada venda para não vender a mesma poltrona duas vezes. O telefone entre elas cai. Agora cada bilheteria decide: para de vender até o telefone voltar (consistente, mas fecha a fila na porta) ou continua vendendo por conta própria (aberta, mas pode vender a poltrona 14 duas vezes). Não existe terceira opção enquanto o telefone estiver mudo — e é exatamente essa a escolha do CAP.
O mal-entendido de sempre
O CAP é quase sempre lido errado, como se você pudesse escolher duas letras de três — 'somos CA'. Não dá. Num sistema distribuído a partição acontece, então P está sempre em jogo; a escolha é só entre C e A durante a partição.
'Somos CA' na prática quer dizer 'não pensamos no que acontece quando a rede parte' — e a rede vai partir. O sistema então escolhe sozinho, no pior momento, e normalmente pela pior opção para aquele caso.
A segunda leitura errada é achar que a escolha é do sistema inteiro, para sempre. Não é. O mesmo banco pode servir uma operação de forma CP (a transferência que não pode duplicar) e outra de forma AP (o contador de visualizações que pode atrasar). Quóruns configuráveis — o clássico R + W > N do Dynamo — são exatamente o botão que move cada operação pelo espectro.
Vale separar CAP de um primo mais útil no dia a dia: o PACELC. Ele estende a ideia dizendo que, mesmo sem partição (o 'Else'), ainda há um trade-off entre latência e consistência — manter as réplicas perfeitamente sincronizadas custa tempo em toda escrita. Na prática, a maioria das decisões de arquitetura é sobre esse lado latência × consistência, que acontece o tempo todo, e não sobre a partição, que é rara.
Por fim, 'consistência' no CAP é a linearizabilidade — toda leitura enxerga a escrita mais recente, como se houvesse um nó só. É uma garantia muito mais forte (e cara) do que o 'C' do ACID, que fala de invariantes dentro de uma transação. Misturar os dois 'C' é a origem de metade da confusão.
Como a escolha aparece na prática
O saldo que preferiu recusar
Cenário
Um sistema de pagamentos replica o saldo em três zonas de disponibilidade. Uma zona fica isolada por uma falha de rede, e chegam débitos que só ela consegue atender localmente.
Como o padrão entra
A operação de débito foi desenhada como CP: exige quórum para confirmar. Durante a partição, os débitos na zona isolada falham com erro claro e o cliente é orientado a tentar de novo — nenhum saldo fica errado.
Trade-off: Parte dos clientes vê indisponibilidade temporária justamente durante o incidente. É o preço aceito conscientemente: para dinheiro, recusar é melhor que divergir.
O carrinho que preferiu responder
Cenário
Um e-commerce guarda o carrinho de compras replicado. Durante uma partição, o mesmo usuário adiciona itens a partir de nós que não conseguem se sincronizar.
Como o padrão entra
O carrinho foi desenhado como AP, seguindo o Dynamo: aceita toda escrita e, quando a rede volta, mescla as versões (a união dos itens). O usuário nunca vê o carrinho quebrado.
Trade-off: A reconciliação pode ressuscitar um item que o usuário tinha removido nos dois lados — o famoso 'item zumbi' do Dynamo. A aplicação precisa de lógica de merge, e ela nem sempre acerta.
Onde isto dá errado
Dizer 'somos CA'
Num sistema distribuído não existe abrir mão de P: a rede parte independentemente da sua vontade. 'CA' quase sempre significa 'não decidimos o que fazer na partição', e aí o sistema decide sozinho — mal — na hora do incidente.
Tratar a escolha como global e permanente
O trade-off é por operação e por configuração, não um carimbo no banco inteiro. Quóruns de leitura e escrita movem o mesmo sistema entre CP e AP; fixar 'este banco é AP' esconde os botões que realmente controlam o comportamento.
Confundir o C do CAP com o C do ACID
No CAP, consistência é linearizabilidade (toda leitura vê a última escrita); no ACID, é preservar invariantes dentro da transação. São garantias diferentes e um sistema pode ter uma sem a outra — misturá-las leva a promessas que ninguém cumpre.
Otimizar para a partição e esquecer a latência
Partição é rara; o trade-off latência × consistência (o lado 'Else' do PACELC) é diário. Manter réplicas sincronizadas em toda escrita custa tempo sempre, e é essa conta, não a da partição, que domina a experiência do usuário.
A escolha na partição
CP recusa; AP responde
// CAP so tem escolha DURANTE uma particao de rede.
// Fora dela, um bom sistema entrega consistencia E disponibilidade.
//
// A pergunta e: quando o no A nao consegue falar com o no B,
// e chega uma leitura, o que A faz?
// CP — recusa em vez de mentir:
async function lerCP(chave: string) {
if (!temQuorum()) {
throw new Error("sem quorum: nao posso garantir o valor atual");
}
return storage.get(chave); // so responde se tem certeza
}
// AP — responde com o que tem, e reconcilia depois:
async function lerAP(chave: string) {
return storage.getLocal(chave); // pode estar velho; nunca recusa
}
// Nenhum dos dois e "melhor". Um extrato bancario prefere CP
// (errar o saldo e pior que esperar); um feed social prefere AP
// (mostrar um like velho e melhor que uma tela de erro).Quando usar × quando evitar
Use quando
3- Ao escolher um banco distribuído e precisar saber como ele se comporta na partição.
- Ao afinar quóruns de leitura e escrita por operação.
- Ao definir, de propósito, o que cada endpoint faz quando a rede parte.
Evite quando
2- Aplicar a um sistema de um nó só, onde não há partição.
- Rotular o banco inteiro de CP ou AP e ignorar a configuração.
Testar o que ficou
4 armadilhas de Teorema CAP viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
Cassandra e DynamoDB (AP)Bancos que preferem responder com um dado possivelmente velho a recusar a escrita durante uma partição de rede.etcd e ZooKeeper (CP)Sistemas de coordenação que preferem recusar a operação a devolver um valor que pode estar desatualizado.quórum R + W > NO botão que move um mesmo banco pelo espectro: quóruns altos compram consistência pagando disponibilidade e latência.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Sob partição, escolha: consistência ou disponibilidade.
// Na prática: timeout curto + degradar leitura.O que ele cobra
Nenhum salto a mais entre a chamada e o efeito.
- Obriga a decidir, por operação, o que fazer durante uma partição — e a maioria dos times nunca decide isso conscientemente
- O lado AP empurra a reconciliação de conflitos para a aplicação, que agora precisa saber mesclar versões divergentes
- O lado CP transforma partição de rede em indisponibilidade visível, que precisa de timeout e retry para não travar o cliente
Não vale se: o sistema roda numa máquina só. Sem rede entre réplicas não há partição, e o CAP simplesmente não se aplica ao seu problema.
Onde isto aparece
Continue por aqui
- Consistência eventualQuando o dado vive em cópias, mantê-las idênticas a cada instante custa latência e disponibilidade. A consistência eventual troca o 'sempre igual' por 'igual daqui a pouco': as réplicas convergem, e o sistema fica mais rápido e mais disponível — ao preço de janelas em que a leitura vê o passado.
- Réplica de leituraQuando as leituras afogam o banco antes das escritas, a saída barata é copiar: o primário recebe todas as escritas e as replica para nós somente-leitura que absorvem as consultas. Escala leitura sem tocar no modelo — ao preço de um atraso de replicação que faz as réplicas verem o passado por um instante.
- Two-Phase Commit (2PC)Como fazer vários bancos commitarem uma transação juntos — ou nenhum. Um coordenador pergunta 'estão prontos?' (prepare), e só manda 'commit' se todos prometeram. Dá atomicidade entre sistemas, ao preço de recursos travados durante todo o protocolo e de um coordenador que, se cair na hora errada, deixa todo mundo travado sem saber o que fazer.