Aprenda o teorema CAP de Eric Brewer como um modelo mental prático: como consistência, disponibilidade e partições moldam decisões em sistemas distribuídos.

Quando você armazena os mesmos dados em mais de uma máquina, ganha velocidade e tolerância a falhas — mas também herda um novo problema: desacordo. Dois servidores podem receber atualizações diferentes, mensagens podem chegar atrasadas ou não chegar, e usuários podem ler respostas diferentes dependendo de qual réplica acessam. O CAP ficou popular porque dá aos engenheiros uma maneira clara de falar sobre essa realidade bagunçada sem rodeios.
Eric Brewer, cientista da computação e cofundador da Inktomi, introduziu a ideia central em 2000 como uma afirmação prática sobre sistemas replicados sob falha. Espalhou-se rapidamente porque correspondia ao que equipes já viviam em produção: sistemas distribuídos não apenas falham ao cair; eles falham ao se dividir.
CAP é mais útil quando algo dá errado — especialmente quando a rede não se comporta. Em um dia saudável, muitos sistemas podem parecer suficientemente consistentes e disponíveis. O teste de pressão é quando máquinas não conseguem se comunicar de forma confiável e você precisa decidir o que fazer com leituras e gravações enquanto o sistema está dividido.
Esse enquadramento é o motivo pelo qual o CAP virou um modelo mental de referência: ele não debate melhores práticas; força uma pergunta concreta — o que sacrificaremos durante uma divisão?
Ao final deste artigo, você deverá ser capaz de:
O CAP perdura porque transforma o vago "distribuído é difícil" em uma decisão que você pode tomar — e defender.
Um sistema distribuído é, em termos simples, muitos computadores tentando agir como um só. Você pode ter vários servidores em diferentes racks, regiões ou zonas de nuvem, mas para o usuário é “o app” ou “o banco de dados”.
Para fazer esse sistema compartilhado funcionar em escala do mundo real, normalmente replicamos: mantemos várias cópias dos mesmos dados em máquinas diferentes.
A replicação é popular por três razões práticas:
Até aqui, replicação parece uma vitória óbvia. O porém é que replicação cria um novo trabalho: manter todas as cópias em acordo.
Se cada réplica pudesse sempre falar com todas as outras instantaneamente, poderiam coordenar atualizações e permanecer alinhadas. Mas redes reais não são perfeitas. Mensagens podem ser atrasadas, descartadas ou roteadas contornando falhas.
Quando a comunicação está saudável, réplicas geralmente trocam atualizações e convergem para o mesmo estado. Mas quando a comunicação quebra (mesmo temporariamente), você pode acabar com duas versões válidas da “verdade”.
Por exemplo, um usuário altera seu endereço de entrega. A réplica A recebe a atualização, a réplica B não. Agora o sistema precisa responder uma pergunta aparentemente simples: qual é o endereço atual?
Esta é a diferença entre:
O pensamento CAP começa exatamente aqui: uma vez que existe replicação, o desacordo sob falha de comunicação não é um caso extremo — é o problema central de projeto.
CAP é um modelo mental para o que os usuários realmente sentem quando um sistema está espalhado por várias máquinas (frequentemente em vários locais). Não descreve sistemas “bons” ou “ruins” — apenas a tensão que você precisa gerenciar.
Consistência é sobre acordo. Se você atualiza algo, a próxima leitura (de qualquer lugar) refletirá aquela atualização?
Do ponto de vista do usuário, é a diferença entre “acabei de mudar e todo mundo vê o novo valor” versus “algumas pessoas ainda veem o valor antigo por um tempo”.
Disponibilidade significa que o sistema responde a requisições — leituras e gravações — com um resultado de sucesso. Não é “o mais rápido possível”, mas “não se recusa a te servir”.
Durante problemas (um servidor fora, um pico de rede), um sistema disponível continua aceitando requisições, mesmo que tenha que responder com dados que podem estar um pouco desatualizados.
Uma partição é quando a rede se divide: máquinas estão em execução, mas mensagens entre algumas delas não conseguem passar (ou chegam tarde demais para serem úteis). Em sistemas distribuídos, você não pode tratar isso como impossível — deve definir comportamento quando isso ocorrer.
Imagine duas lojas que vendem o mesmo produto e compartilham “1 contagem de inventário”. Um cliente compra o último item na Loja A, então a Loja A grava estoque = 0. Ao mesmo tempo, uma partição de rede impede que a Loja B saiba disso.
Se a Loja B permanecer disponível, pode vender um item que não tem mais (aceitando a venda enquanto particionada). Se a Loja B impor consistência, pode recusar a venda até confirmar o inventário mais recente (negando serviço durante a divisão).
Uma “partição” não é apenas “a internet caiu”. É qualquer situação em que partes do seu sistema não conseguem se comunicar de forma confiável — mesmo que cada parte continue rodando normalmente.
Em um sistema replicado, nós trocam mensagens constantemente: gravações, confirmações, heartbeats, eleições de líder, requisições de leitura. Uma partição é o que acontece quando essas mensagens param de chegar (ou chegam tarde demais), criando desacordo sobre a realidade: “A gravação aconteceu?” “Quem é o líder?” “O nó B está vivo?”
A comunicação pode falhar de formas confusas e parciais:
O ponto importante: partições costumam ser degradação, não uma queda limpa. Do ponto de vista da aplicação, “lento o suficiente” pode ser indistinguível de “fora do ar”.
À medida que você adiciona mais máquinas, mais redes, mais regiões e mais partes móveis, há simplesmente mais oportunidades para a comunicação quebrar temporariamente. Mesmo que componentes individuais sejam confiáveis, o sistema como um todo experimenta falhas porque tem mais dependências e mais coordenação entre nós.
Você não precisa assumir uma taxa de falha exata para aceitar a realidade: se seu sistema roda tempo suficiente e abrange bastante infraestrutura, partições vão acontecer.
Tolerância a partições significa que seu sistema é projetado para continuar operando durante uma divisão — mesmo quando nós não conseguem concordar ou confirmar o que o outro lado viu. Isso força uma escolha: continuar atendendo requisições (arriscando inconsistência) ou parar/rejeitar algumas requisições (preservando consistência).
Uma vez que você tem replicação, uma partição é simplesmente uma quebra de comunicação: duas partes do seu sistema não conseguem falar de forma confiável por um tempo. Réplicas continuam em execução, usuários continuam clicando e seu serviço continua recebendo requisições — mas as réplicas não conseguem concordar sobre a verdade mais recente.
Essa é a tensão do CAP em uma frase: durante uma partição, você deve escolher priorizar Consistência (C) ou Disponibilidade (A). Você não obtém ambos ao mesmo tempo.
Você está dizendo: 'prefiro estar correto a ser responsivo.' Quando o sistema não consegue confirmar que uma requisição manterá todas as réplicas em sincronia, ela deve falhar ou esperar.
Efeito prático: alguns usuários veem erros, timeouts ou mensagens de 'tente novamente' — especialmente para operações que alteram dados. Isso é comum quando você prefere rejeitar um pagamento do que arriscar cobrar duas vezes, ou bloquear uma reserva de assento do que vender em excesso.
Você está dizendo: 'prefiro responder a bloquear.' Cada lado da partição continuará aceitando requisições, mesmo que não possa coordenar.
Efeito prático: usuários recebem respostas de sucesso, mas os dados que leem podem estar desatualizados, e atualizações concorrentes podem conflitar. Você então depende de reconciliação posterior (regras de merge, last-write-wins, revisão manual etc.).
Isso não é sempre uma configuração global. Muitos produtos misturam estratégias:
O momento chave é decidir — por operação — o que é pior: bloquear um usuário agora ou consertar uma verdade conflituosa depois.
O slogan 'escolha dois' é memorável, mas frequentemente engana as pessoas a pensar que CAP é um cardápio de três recursos onde você só pode manter dois para sempre. CAP trata do que acontece quando a rede para de cooperar: durante uma partição (ou qualquer coisa que pareça com uma), um sistema distribuído deve escolher entre retornar respostas consistentes e permanecer disponível para toda requisição.
Em sistemas distribuídos reais, partições não são uma configuração que você pode desativar. Se seu sistema abrange máquinas, racks, zonas ou regiões, mensagens podem ser atrasadas, descartadas, reordenadas ou roteadas de forma estranha. Isso é uma partição do ponto de vista do software: nós não conseguem concordar sobre o que está acontecendo.
Mesmo que a rede física esteja bem, falhas em outros lugares criam o mesmo efeito — nós sobrecarregados, pausas de GC, vizinhos barulhentos, hiccups de DNS, load balancers instáveis. O resultado é o mesmo: partes do sistema não conseguem falar entre si o suficiente para coordenar.
Aplicações não experimentam 'partição' como um evento binário e limpo. Elas experimentam picos de latência e timeouts. Se uma requisição expira após 200 ms, não importa se o pacote chegou aos 201 ms ou nunca chegou: a aplicação precisa decidir o que fazer a seguir. Do ponto de vista da aplicação, comunicação lenta muitas vezes é indistinguível de comunicação quebrada.
Muitos sistemas reais são maioritariamente consistentes ou maioritariamente disponíveis, dependendo da configuração e das condições de operação. Timeouts, políticas de retry, tamanhos de quórum e opções como 'read your writes' podem alterar o comportamento.
Em condições normais, um banco de dados pode parecer fortemente consistente; sob estresse ou problemas entre regiões, ele pode começar a falhar requisições (favorecendo consistência) ou retornar dados antigos (favorecendo disponibilidade).
CAP é menos sobre rotular produtos e mais sobre entender o trade-off que você está fazendo quando o desacordo acontece — especialmente quando esse desacordo é causado por lentidão comum.
Discussões sobre CAP frequentemente fazem a consistência parecer binária: ou 'perfeita' ou 'vale tudo'. Sistemas reais oferecem um cardápio de garantias, cada uma com uma experiência diferente quando réplicas discordam ou um link de rede quebra.
Consistência forte (frequentemente 'linearizável') significa que, uma vez que uma gravação é reconhecida, toda leitura posterior — não importa qual réplica seja atingida — retorna essa gravação.
O custo: durante uma partição ou quando uma minoria de réplicas está inacessível, o sistema pode atrasar ou rejeitar leituras/gravações para evitar mostrar estados conflitantes. Usuários notam isso como timeouts, 'tente novamente' ou comportamento temporariamente somente leitura.
Consistência eventual promete que, se não houver novas atualizações, todas as réplicas convergirão. Não promete que dois usuários lendo agora verão a mesma coisa.
O que os usuários podem notar: uma foto de perfil atualizada que 'reverte', contadores que ficam defasados ou uma mensagem enviada que não aparece em outro dispositivo por alguns instantes.
Você frequentemente pode obter uma experiência melhor sem exigir consistência forte completa:
Essas garantias se alinham bem com como as pessoas pensam ('não me mostre minhas próprias mudanças sumindo') e podem ser mais fáceis de manter durante falhas parciais.
Comece com promessas ao usuário, não com jargão:
Consistência é uma escolha de produto: defina o que é 'errado' para o usuário e então escolha a garantia mais fraca que previne esse erro.
Disponibilidade no CAP não é um número de exibição ('cinco noves') — é uma promessa que você faz aos usuários sobre o que acontece quando o sistema não pode ter certeza.
Quando réplicas não conseguem concordar, você frequentemente escolhe entre:
Os usuários sentem isso como 'o app funciona' versus 'o app está correto'. Nenhum é universalmente melhor; a escolha certa depende do que significa ‘estar errado’ no seu produto. Um feed social levemente desatualizado é irritante. Um saldo bancário desatualizado pode ser danoso.
Dois comportamentos comuns aparecem na incerteza:
Isso não é puramente técnico; é uma decisão de política. O produto precisa definir o que é aceitável mostrar e o que nunca deve ser chutado.
Disponibilidade raramente é tudo ou nada. Durante uma divisão, você pode ver disponibilidade parcial: algumas regiões, redes ou grupos de usuários têm sucesso enquanto outros falham. Isso pode ser um design deliberado (continuar servindo onde a réplica local está saudável) ou um efeito acidental (desequilíbrios de roteamento, alcance desigual de quóruns).
Um meio-termo prático é o modo degradado: continuar servindo ações seguras enquanto restringe as arriscadas. Por exemplo, permitir navegação e busca, mas desativar temporariamente 'transferir fundos', 'mudar senha' ou outras operações onde correção e unicidade importam.
CAP parece abstrato até você mapear para o que seus usuários experimentam durante uma divisão de rede: prefere que o sistema continue respondendo ou que pare para evitar dados conflitantes?
Imagine dois datacenters aceitando pedidos enquanto não conseguem se comunicar.
Se você mantém o checkout disponível, cada lado pode vender o “último item” e você fará oversell. Isso pode ser aceitável para mercadorias de baixo risco (você faz backorder ou pede desculpas), mas doloroso para lançamentos limitados.
Se optar por consistência primeiro, pode bloquear novos pedidos quando não consegue confirmar o estoque globalmente. Usuários veem 'tente novamente mais tarde', mas você evita vender o que não pode cumprir.
Dinheiro é o domínio clássico onde estar errado é caro. Se duas réplicas aceitarem saques de forma independente durante uma partição, uma conta pode ficar negativa.
Sistemas frequentemente preferem consistência em gravações críticas: recusar ou atrasar ações se não conseguir confirmar o saldo mais recente. Você troca um pouco de disponibilidade (falhas temporárias no pagamento) por correção, auditabilidade e confiança.
Em chat e feeds sociais, usuários geralmente toleram pequenas inconsistências: uma mensagem chega alguns segundos depois, um contador de curtidas está desatualizado, uma métrica aparece mais tarde.
Aqui, projetar para disponibilidade pode ser uma boa escolha de produto, desde que você seja claro sobre quais elementos são 'eventualmente corretos' e consiga mesclar atualizações de forma limpa.
A escolha certa do CAP depende do custo de estar errado: reembolsos, exposição legal, perda de confiança do usuário ou caos operacional. Decida onde você pode aceitar desfase temporário — e onde precisa falhar fechado.
Depois de decidir o que fará durante uma divisão de rede, você precisa de mecanismos que tornem essa decisão real. Esses padrões aparecem em bancos de dados, sistemas de mensagens e APIs — mesmo que o produto nunca mencione 'CAP'.
Um quórum é simplesmente 'a maioria das réplicas concorda'. Se você tem 5 cópias, a maioria é 3.
Ao exigir que leituras e/ou gravações contatem uma maioria, você reduz a chance de retornar dados desatualizados ou conflitantes. Por exemplo, se uma gravação precisa ser reconhecida por 3 réplicas, é mais difícil para dois grupos isolados aceitarem verdades diferentes.
O trade-off é velocidade e alcance: se você não consegue atingir a maioria (por causa de partição ou falhas), o sistema pode recusar a operação — escolhendo consistência sobre disponibilidade.
Muitos problemas de 'disponibilidade' não são falhas definitivas, mas respostas lentas. Definir um timeout curto pode fazer o sistema parecer ágil, mas também aumenta a chance de tratar sucessos lentos como falhas.
Retries podem recuperar blips transitórios, mas retries agressivos podem sobrecarregar um serviço já em sofrimento. Backoff (esperar mais entre tentativas) e jitter (aleatoriedade) ajudam a evitar que retries virem um pico de tráfego.
A chave é alinhar essas configurações com sua promessa: 'sempre responder' geralmente significa mais retries e fallbacks; 'nunca mentir' geralmente significa limites mais rígidos e erros claros.
Se você optar por permanecer disponível durante partições, réplicas podem aceitar atualizações diferentes e você precisa reconciliar depois. Abordagens comuns incluem:
Retries podem criar duplicações: cobrar um cartão duas vezes ou submeter um pedido duplicado. Idempotência previne isso.
Um padrão comum é a chave de idempotência (request ID) enviada com cada requisição. O servidor armazena o primeiro resultado e retorna o mesmo resultado para repetições — assim retries melhoram disponibilidade sem corromper dados.
A maioria das equipes 'escolhe' uma postura CAP em um quadro branco — e descobre em produção que o sistema se comporta diferente sob estresse. Validar significa criar intencionalmente as condições onde os trade-offs do CAP ficam visíveis e checar se seu sistema reage como projetado.
Você não precisa de um corte de cabo real para aprender algo. Use injeção de falhas controlada em staging (e com cuidado em produção) para simular partições:
O objetivo é responder perguntas concretas: gravações são rejeitadas ou aceitas? leituras retornam dados antigos? o sistema se recupera automaticamente e quanto tempo leva a reconciliação?
Se quiser validar esses comportamentos cedo (antes de investir semanas integrando serviços), pode ajudar montar um protótipo realista rapidamente. Por exemplo, equipes muitas vezes começam gerando um serviço pequeno (comummente um backend em Go com PostgreSQL e uma UI React) e então iteram sobre retries, chaves de idempotência e fluxos de 'modo degradado' em um ambiente sandbox.
Checks tradicionais de uptime não capturam comportamento 'disponível mas errado'. Monitore:
Operadores precisam de ações pré-definidas quando uma partição ocorre: quando congelar gravações, quando fazer failover, quando degradar funcionalidades e como validar a segurança da re-mesclagem.
Também planeje o comportamento exposto ao usuário. Se você escolher consistência, a mensagem pode ser 'Não conseguimos confirmar sua atualização — por favor tente novamente.' Se escolher disponibilidade, seja explícito: 'Sua atualização pode demorar alguns minutos para aparecer em todos os lugares.' Redigir isso claramente reduz carga de suporte e preserva confiança.
Quando estiver tomando uma decisão de sistema, o CAP é mais útil como uma auditoria rápida do 'o que quebra durante uma divisão?' — não um debate teórico. Use este checklist antes de escolher um recurso de banco de dados, estratégia de cache ou modo de replicação.
Pergunte nesta ordem:
Se uma partição ocorrer, você estará decidindo quais desses proteger primeiro.
Evite uma configuração global única como 'somos um sistema AP'. Em vez disso, decida por:
Exemplo: durante uma partição, você pode bloquear gravações em payments (prefere consistência) mas manter leituras de product_catalog disponíveis com cache.
Escreva o que você tolera, com exemplos:
Se você não consegue descrever a inconsistência em exemplos simples, será difícil testar e explicar incidentes.
Próximos temas que combinam bem com este checklist: consenso (/blog/consensus-vs-cap), modelos de consistência (/blog/consistency-models-explained) e SLOs/orçamentos de erro (/blog/sre-slos-error-budgets).
CAP é um modelo mental para sistemas replicados sob falha de comunicação. É mais útil quando a rede está lenta, com perda de pacotes ou dividida, porque é quando os réplicas não conseguem concordar e você é forçado a escolher entre:
Ajuda a transformar o “sistemas distribuídos são difíceis” em uma decisão concreta de produto e engenharia.
Um cenário CAP verdadeiro exige ambas as condições:
Se seu sistema for um único nó, ou se você não replica estado, os trade-offs do CAP não são o problema central.
Uma partição é qualquer situação em que partes do seu sistema não conseguem se comunicar de forma confiável ou dentro dos limites de tempo exigidos — mesmo que todas as máquinas ainda estejam funcionando.
Na prática, "partição" costuma se manifestar como:
Do ponto de vista da aplicação, “muito lento” pode ser igual a “fora do ar”.
Consistência (C) significa que leituras refletem a gravação mais recente reconhecida de qualquer lugar. Os usuários experienciam isso como 'Eu mudei e todo mundo vê'.
Disponibilidade (A) significa que toda requisição recebe uma resposta bem-sucedida (não necessariamente o dado mais novo). Os usuários sentem como 'o app continua funcionando', possivelmente com resultados desatualizados.
Durante uma partição, normalmente não é possível garantir ambos simultaneamente para todas as operações.
Porque partições não são opcionais em sistemas distribuídos que abrangem máquinas, racks, zonas ou regiões. Se você replica, precisa definir comportamento quando nós não conseguem coordenar.
Portanto, “tolerar partições” geralmente significa: quando a comunicação falhar, o sistema ainda tem um modo de operar — ou rejeitando/pausando algumas ações (favorecendo consistência) ou servindo resultados aproximados (favorecendo disponibilidade).
Se você favorece consistência, normalmente você:
Isso é comum para movimentações de dinheiro, reserva de inventário e mudanças de permissões — lugares onde estar errado é pior do que ficar temporariamente indisponível.
Se você favorece disponibilidade, normalmente você:
Os usuários veem menos erros duros, mas podem ver dados desatualizados, efeitos duplicados sem idempotência ou conflitos que exigem limpeza.
Você pode escolher de forma diferente por endpoint/tipo de dado. Estratégias comuns misturadas incluem:
Isso evita um único rótulo global 'somos AP/CP' que raramente corresponde às necessidades reais do produto.
Opções úteis incluem:
Valide criando condições onde o desacordo se torne visível:
Escolha a garantia mais fraca que impede um 'erro' visível ao usuário que você não tolera.
Também prepare runbooks e mensagens ao usuário que correspondam ao comportamento escolhido (fail closed vs fail open).