NoSQL – Do teorema CAP para P?(A|C):(C|L)

Existem muitas motivações para os bancos NoSQL, como por exemplo usar um modelo mais adequado para os seu dados ou facilitar alterações de schema; ou ainda além, melhorar o desempenho e simplificar a replicação para ter a tão sonhada escalabilidade linear.

O teorema CAP

Claro que todos os benefícios não vem sem custo, comparado com os bancos de dados tradicionais vamos perder alguma funcionalidade/garantia para ganhar outra. O tradeoff arquitetural é descrito no bem conhecido CAP theorem.

A palestra famosa do Dr. Eric Brewer introduz o teorema e explica que em qualquer sistema distribuído stateful é preciso escolher entre consistência forte (C – Consistency), alta disponibilidade (A – availability) e tolerância a particionamento dos dados na rede(P – Network Partition Tolerance). Segundo o teorema CAP, entre as três propriedades, somente duas podem ser garantidas ao mesmo tempo:

Partition-Tolerance

Poder particionar nossos dados em diferentes nós de um cluster é um dos recursos que aparecem com frequência nos bancos NoSQL. Saber lidar com a separação/particionamento das dados devido uma falha na rede é conhecido como Partition-Tolerant. No entanto, segundo o teorema CAP, em troca eles irão sacrificar a consistência forte ou a alta disponibilidade. Isso é diferente dos bancos tradicionais, que não possuem essa característica no design do sistema ou delegam isso para o filesystem.

NoSQL 1: Sistemas CP

Para sistemas que precisam da consistência forte e tolerância a particionamento (CP) é necessário abrir a mão da disponibilidade (um pouco). Pode acontecer, caso haja particionamento e o sistema não entre em consenso, que uma escrita seja rejeitada. Claro que os sistemas tentam evitar isso ao máximo, tanto que não costuma existir, por exemplo, uma transação distribuída e sim um protocolo de consensos para garantir a consistência forte. Exemplos desses sistemas CP são BigTable, HBase ou MongoDB entre vários outros.

NoSQL 2: Sistemas AP

Por outro lado existem sistemas que jamais podem ficar offline (24/7), portanto não desejam sacrificar a disponibilidade. Para ter alta disponibilidade mesmo com um tolerância a particionamento (PA) é preciso prejudicar a consistência (eventual-consistency). A ideia aqui é que os sistemas aceitam escritas sempre e tentam sincronizar os dados em algum momento depois (read-consistency). Então pode ter uma janela de inconsistência. Exemplos aqui são Amazon Dynamo, Cassandra ou Riak.

Sistemas CA

Os sistemas com consistência forte e alta disponibilidade (CA) (alta disponibilidade de um nó apenas) não sabem lidar com a possível falha de uma partição. Caso ocorra, sistema inteiro pode ficar indisponível até o membro do cluster voltar. Exemplos disso são algumas configurações clássicas de bancos relacionais.

Qual é a diferença entra CA e CP?

Vimos brevemente o teorema CAP e a escolha que os sistemas NoSQL fazem (CP ou AP) comparado com os bancos tradicionais (CA). É importante mencionar que para o desenvolvedor não haverá tantas diferenças entre CA ou CP. SEMPRE teremos consistência forte, no entanto, um sistema fica indisponível (CA) quando há particionamento – pois tem apenas alta disponibilidade por nó – e o outro sistema (CP) tente chegar a um consenso se aceita uma escrita ou não, que no pior dos casos também pode significar a indisponibilidade para uma parte dos dados. Seguindo desse raciocínio podemos perceber que a consistência e disponibilidade são extremos quando há particionamento. Isso foi uma dúvida que me incomodou bastante antes da minha palestra no Caelumday 2009. Podemos concluir que quando há particionamento (P) terá alta disponibilidade (A) ou consistência (C) forte: P?(A|C)

Mas o que acontece se NĀO há particionamento?

É uma pergunta que o CAP não responde. A primeira resposta poderia ser: claro que vai ser consistente já que ninguém gosta de lidar com dados desatualizados. Mas olhando para os sistemas NoSQL nem sempre isso é verdade. Existem sistemas que SEMPRE são eventually-consistent. Mas porque?

Consistência ou Latência

Há mais um motivo porque poderia fazer sentido sacrificar a consistência: O tempo da resposta ou a latência. Da mesma maneira que um sistema offline pode custar caro, um sistema lento também pode. Por isso pode fazer sentido abrir a mão da consistência para diminuir a latência.

De CAP para PAC/CL

O artigo do blog do Prof. Daniel Abadi explica o tradeoff com partições e sem. Ele sugere substituir a sigla CAP com PAC/CL (ou P?(A|C):(C|L)), traduzindo levemente modificado do artigo dele:

“… se há particionamento (P), o sistema pode valorizar a disponibilidade (A) ou a consistência (C), senão, quando o sistema roda sem partições, o sistema pode favorecer o tempo da resposta/latência (L) ou a consistência (C).”

Exemplos de PAC/CL

Seguindo dessa linha PC/C significa que o sistema valoriza a consistência sempre, com ou sem partições. Banco de dados tradicionais são sempre fortemente consistentes, ou seja PC/C. Amazon Dynamo ou Cassandra são sempre fracamente consistente, favorecendo a alta disponibilidade e o tempo da resposta (latência), ou seja PA/L. Mas existem misturas como o GenieDB (PA/C), que só trabalha consistente em caso de nenhuma partições. Quando há partições valoriza a alta disponibilidade. Exemplo contrário disso é o Yahoo Sherpa, que usa PC/L, ou seja com partições favorece consistência, sem partições diminuir a latência.

Durante o curso FJ-91, diversas questões e decisões arquiteturais são abordadas e discutidas, sendo que uma delas envolve o teorema CAP e os bancos de dados NoSQL.

5 Comentários

  1. Samuel 08/12/2011 at 12:47 #

    O aprendizado de uma nova tecnologia ou metodologia envolve mutio mais que simplismente estudar uma nova api, envolve novos conceitos e formas de pensar.
    Ótimo tutorial e gostaria de dar umas dicas pra outros tutoriais:
    Quando usar um Banco de Dados orientado a Documentos;
    entendendo e usando o fail-tolerance do MongoDb;
    Entendendo o Column Oriented do Cassandra;
    Desde já agradeço.

  2. Diogo Baeder 09/12/2011 at 03:31 #

    Passei por uma situação curiosa, que tem relação com isto que você escreveu sobre latência: desenvolvendo uma aplicação com Tornado, PyPy e MongoDB, durante o desenvolvimento de testes funcionais automatizados, eu estava com dificuldade de fazer um teste passar. Até que me deu uma ideia: coloquei um sleep no meio do teste, logo após criar um documento no MongoDB. Funcionou, o problema era que o sistema estava mais rápido do que o tempo do MongoDB de criar o documento.

    Excelente artigo, aliás! Parabéns! :-)

  3. elias 25/06/2012 at 02:12 #

    “Poder particionar nossos dados em diferentes nós de um cluster é um dos recursos que aparecem com frequência nos bancos NoSQL. e são conhecidos como Partition-Tolerant”

    Isto não é verdade. Ser tolerante ao particionamento é o mesmo que o banco de dados continuar operando ainda que exista uma falha na rede que isole (particione) o banco em duas ou mais redes independentes.

    Uma outra coisa: existe uma diferença conceitual ao desenvolvedor entre CA e CP. A disponibilidade do “A” significa que o sistema sempre responderá se determinada operação foi bem sucedida ou não. Então um sistema CA sempre irá dizer se a requisição foi bem sucedida ou não.

    Sistemas CP, que são consistentes e tolerantes ao particionamento, ao receberem uma requisição de escrita, podem não ter como responder ao cliente se esta requisição será bem sucedida ou não – por causa do “C” algumas requisições terão de ser descartadas, e por causa do “P” o sistema tem que operar mesmo quando não tem como ter certeza se quando a rede se juntar novamente, o dado precisará ser descartado.

    Em um caso, o programa efetuará operações sem ter certeza se elas serão processadas, no outro o banco irá negar o processamento de operações se não tiver certeza de que poderá cumpri-las.

  4. Nico Steppat 25/06/2012 at 06:32 #

    @Elias
    Para mim o P (Partition tolerance) é se o sistema sabe ou nao lidar com duas particoes na rede que separam o sistema.

    Essa caracteristica entrou no design dos sistemas NoSQL e eles estao preparados caso aconteca (como vc falou). Agora há a abordagem otimista (CA – escritas nunca falham) e pessimista (CP – escritas podem ser negadas).

    A frase no meu texto realmente nao está clara.

    Obrigado pelo comentário.

Deixe uma resposta