O teorema de CAP, também conhecido como o teorema de Brewer, é um conceito fundamental em sistemas distribuídos. Ele afirma que um sistema distribuído não pode garantir simultaneamente todas as três seguintes propriedades:
Consistência (Consistency): Todos os nós do sistema veem os mesmos dados ao mesmo tempo. Isso significa que uma leitura sempre retorna o valor mais recente após uma escrita bem-sucedida.
Disponibilidade (Availability): Cada solicitação feita ao sistema recebe uma resposta, mesmo que algumas partes do sistema estejam indisponíveis. Ou seja, o sistema está sempre operacional.
Tolerância a Partições (Partition Tolerance): O sistema continua a operar mesmo se houver falhas de comunicação ou "partições" na rede que impedem que os nós se comuniquem entre si.
Dado que falhas de rede (partições) são inevitáveis em sistemas distribuídos reais, um sistema sempre terá que priorizar entre Consistência e Disponibilidade. É impossível atingir simultaneamente as três propriedades em um sistema que está sujeito a falhas de comunicação. Exemplos de sistemas distribuídos:
Sacrificam a disponibilidade. Quando ocorre uma partição, o sistema pode se tornar indisponível para manter a consistência.
Exemplo: Bancos de dados como HBase, MongoDB configurado para consistência forte.
Sacrificam a consistência. Durante uma partição, os nós podem responder com dados desatualizados (inconsistentes).
Exemplo: Sistemas como Cassandra, DynamoDB.
Não toleram partições. Esses sistemas dependem de redes confiáveis e falhas podem tornar o sistema completamente indisponível.
Exemplo: Sistemas centralizados, como alguns bancos de dados relacionais.
Nenhum sistema distribuído pode ter 100% de consistência, disponibilidade e tolerância a partições ao mesmo tempo. Os desenvolvedores precisam decidir qual propriedade priorizar com base nos requisitos do sistema. Por exemplo:
- Um sistema financeiro pode priorizar consistência (CP).
- Um sistema de redes sociais pode priorizar disponibilidade (AP).
Essa escolha é muitas vezes contextual e depende das necessidades específicas da aplicação e do ambiente onde ela opera.
Configurar um cluster de um banco de dados distribuído, como o Cassandra (AP) ou o MongoDB (CP). Em seguida, simular partições de rede e observar o comportamento do sistema em termos de consistência, disponibilidade e tolerância a partições
Certifique-se de que o Docker está instalado no seu ambiente. Guia oficial de instalação.
Aqui, usaremos MongoDB como exemplo, configurado para replicação (um cluster com réplicas).
Criar a rede Docker:
docker network create cap-testSubir três instâncias do MongoDB:
docker run -d --name mongo1 --network cap-test mongo --replSet rs0
docker run -d --name mongo2 --network cap-test mongo --replSet rs0
docker run -d --name mongo3 --network cap-test mongo --replSet rs0Ou inicialize tudo pelo docker compose
docker compose upInicializar o cluster de réplicas: Conecte-se ao container mongo1 para configurar o cluster:
docker exec -it mongo1 mongoshNo shell do MongoDB:
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo1:27017" },
{ _id: 1, host: "mongo2:27017" },
{ _id: 2, host: "mongo3:27017" }
]
});1. Testar Consistência e Partição (CP):
- Simule uma partição de rede desconectando um dos nós:
docker network disconnect cap-test mongo2- Tente realizar leituras e escritas no cluster. Por padrão, o MongoDB prioriza consistência e pode se tornar indisponível para certas operações até resolver a partição
2. Testar Disponibilidade e Partição (AP):
- Configure o MongoDB para permitir operações de escrita mesmo em caso de partição. No mongo1, execute:
rs.status().members.map(i => ({ name: i.name, health: i.health, state: i.stateStr }));- Simule uma partição novamente:
docker network disconnect cap-test mongo3- Realize leituras e escritas. Você pode observar que algumas leituras podem retornar dados desatualizados.
3. Testar Consistência e Disponibilidade (CA):
- Sem simular partições, observe que o MongoDB mantém consistência e disponibilidade.
Acompanhe os logs dos containers para entender o comportamento durante as partições:
docker logs -f mongo1
docker logs -f mongo2
docker logs -f mongo3Após os testes, remova os containers e a rede:
docker rm -f mongo1 mongo2 mongo3
docker network rm cap-testou
docker compose downEsse experimento ajuda a visualizar como sistemas distribuídos priorizam Consistência, Disponibilidade ou Tolerância a Partições em cenários reais. Com pequenos ajustes, você pode usar outros sistemas distribuídos, como Cassandra, Redis Cluster ou Etcd, para explorar diferentes comportamentos CAP.