Arquivo da tag: NewSQL

Teorema CAP

Atualmente existem mais de 300 bancos de dados no mercado, e você precisa escolher aquele que melhor atende sua necessidade.

Os projetistas desses bancos de dados fizeram uma importante decisão sobre como eles devem funcionar, e por isso é importante entender o mecanismo de funcionamento deles para você não errar na escolha.

Entendendo o Teorema CAP você terá uma visão mais clara sobre os tipos de bancos de dados disponíveis, e quais estão aderentes ao seu caso de uso.

Nesse post eu passo uma visão básica sobre o significado do Teorema CAP. Você também pode assistir meu video no YouTube:

Consistency, Availability and Partition Tolerance (CAP)

CAP significa Consistência [do inglês, Consistency], Disponibilidade [do inglês, Availability], e Tolerância a Partição [do inglês, Partition Tolerance].

Partition Tolerance significa que o banco de dados é distribuído em diversos servidores independentes [shared-nothing], em pares de leitura/escrita. Isso é importante, em especial, para aumentar a performance, já que quanto mais você espalha os dados em servidores diferentes, maior é o throughput [megabytes por segundo] de leitura e escrita. Partition Tolerance também significa que se um servidor estiver fora, todo o sistema de banco de dados continua funcionando, com exceção desta parte específica que apresentou a falha.

Você pode perguntar por que P é chamado exatamente de “Tolerância a Partição”. O entendimento de partição aqui é “falha”, e mais especificamente falha de rede, que impede que um servidor se comunique com outro servidor. Então quando um banco de dados tolera partição, significa que se houver falha na comunicação entre um servidor que escreve e sua réplica, o banco de dados não para de funcionar, pois poderá haver outros pares de leitura e escrita no cluster que não estão no caminho da rede que falhou.

Consistency implica em consistência de leitura, e significa que depois que uma informação é escrita, todas as leituras subsequentes vão enxergá-la, no mesmo servidor, ou em suas réplicas. Neste caso também dizemos que há consistência forte, porque todos enxergam a mesma versão da informação.

Availability significa sempre disponível para leitura ou escrita, e todas as requisições sempre retornam alguma informação, mesmo que ela esteja inconsistente – mas nunca retorna um erro. Isto é, pode ter havido alguma falha na rede e os pares de servidores leitura/escrita não se enxergam, mas ambos permanecem abertos e recebem operações, estando em estado eventualmente consistente. Por causa disso, também dizemos que há uma consistência eventual, porque não é certeza que todos enxergam a mesma versão da informação.

A Prova

O Teorema CAP foi provado, e ele diz que das três propriedades desejadas, apenas duas podem existir ao mesmo tempo para um par leitura/escrita.

Isso nos leva a três possibilidades que definem o mecanismo de funcionamento de um banco de dados.

CA – Consistency e Availability: são bancos de dados cujos dados não estão distribuídos, mas oferecem consistência, e também disponibilidade [porém, em geral através de failover, isto é, com downtime]. O Oracle RAC é o único atualmente que oferece tanto C como A “sem downtime” em um sistema de banco de dados que não tolera partição [shared-disk].

CP – Consistency e Partition Tolerance: são bancos de dados que oferecem consistência, isto é, os pares leitura/escrita sempre estão com os mesmo dados [consistentes], mas caso haja alguma falha na rede, ambos tornam-se indisponíveis: sacrificam a disponibilidade em favor da consistência.

AP – Availability e Partition Tolerance: são bancos de dados que oferecem disponibilidade, e sacrificam a consistência. Isto é, os pares leitura/escrita permanecem operantes quando há falha na rede. Notadamente, quando isto ocorre eles ficam em estado inconsistente, pois não há uma comunicação entre eles. A inconsistência pode ser resolvida quando a comunicação é reestabelecida.

Minha Opinião… e a Sua?

Primeiramente, a letra A do CAP implica em uma premissa que eu particularmente não concordo.

A significa sempre disponível para leitura e escrita, mas sabemos que disponibilidade é medida em 9s depois da vírgula, e nada é realmente 100%. Quanto mais rotas redundantes de rede, e mais réplicas dos dados, mais 9s de disponibilidade teremos depois da vírgula, mas nunca 100% como o teorema preconiza.

Um outro ponto é que potencialmente, salvo implementação específica de cada banco de dados, os sistemas AP sempre apresentam um estado de consistência eventual, mesmo sem falha/partição na rede. Isso ocorre porque a propagação dos dados entre o servidor de que escreve e o servidor de réplica é assíncrona. Desta forma uma leitura pode ocorrer antes que uma informação que acabara de ser escrita fosse transmitida pela rede até o servidor em questão. Considerando que atualmente falhas de rede são raras, e as redes de comunicação locais são rápidas, sistemas AP oferecem uma desvantagem permanente, e na minha visão, desnecessária, tornando-os nicho para necessidades muito específicas. Há uma tendência de mercado dos bancos de dados NoSQL migrarem para o paradigma CP.

Então antes de usar um banco de dados, em especial nesses tempos de micro-serviços e persistência poliglota, atente-se ao mecanismo que é implementado no banco de dados.

Requisitos de elasticidade e alto throughput para leitura e escrita exigem que o banco de dados seja tolerante a partições. E neste caso, se houver a necessidade de consistência forte, o banco de dados deverá ser CP, do contrário, escolha AP.

Um Panorama Sobre os Tipos de Banco de Dados para Você Ficar por Dentro

Sistemas de banco de dados são como vinhos, queijos e árvores. Eles melhoram enquanto envelhecem.


Em um projeto complexo, com requisitos de alta performance, escalabilidade e disponibilidade para a camada de persistência, de todas as decisões que você deve tomar, nenhuma é mais desafiadora – e nenhuma outra tem recebido mais atenção – do que ESCOLHER O BANCO DE DADOS MAIS ADEQUADO [a engenharia do Uber que o diga]. O que torna tal decisão tão difícil não é só a quantidade de opções que existe [são mais de 300 bancos de dados para os mais diversos fins].

Os sistemas Relacionais são os mais populares, suportam nativamente SQL [que é a melhor linguagem para consultar e manipular dados], e são os melhores em integridade – mas sabidamente eles não escalam de forma eficiente, e têm baixa flexibilidade. Os sistemas NoSQL escalam horizontalmente, são extremamente flexíveis e suportam dados variados, mas pecam na consistência [que é eventual]. Os sistemas NewSQL são um avanço dos NoSQL, têm maior consistência, maior suporte ao SQL, porém com menor disponibilidade em relação ao anterior. Os sistemas Multi-Model são uma combinação do Relacional com o NoSQL, porém não absorvem todas as características de arquitetura de cada um. Multi-Model é uma capacidade que todos os anteriores podem ter.

A GRANDE DIFICULDADE está em escolher aquele que atenda aos requisitos atuais, MAS QUE TAMBÉM ATENDA AOS REQUISITOS FUTUROS que você ainda não sabe quais são. Isso pode te deixar na mão se o sistema de banco de dados escolhido não tiver a capacidade de se adequar ao dinamismo que estamos vivenciando, como desenvolvimento ágil, microserviços, aplicações cloud native, machine learning, blockchain e IoT.

Pare por um momento e responda: Você Tem Dúvidas para Decidir Qual é a Camada de Persistência Mais Adequada para seu Próximo Projeto? Espero que este panorama lhe ajude a ter uma visão mais clara.

Relacional é SQL, e SQL é Relacional: uma Simbiose dos Anos 70 que é Atual até Hoje

SQL e o sistema de banco de dados Relacional transformaram em museu rapidamente tudo que existia antes. Inovações como acesso client/server, joins, locks no nível de linha, leitura consistente, transações locais e distribuídas, e constraints, só para citar alguns, foram capazes de aliviar os desenvolvedores da época, e substituir milhares de linhas de código por uma simples frase: SELECT FROM WHERE. A evolução do SQL foi um dos acontecimentos mais importantes na década de 80 na área de tecnologia, pois mudou a forma como a informação era utilizada, e como os sistemas eram construídos.

A linguagem SQL e o sistema Relacional surgiram, e milhares de linhas de código foram substituídas por uma simples frase: SELECT FROM WHERE.

A linguagem SQL, utilizada para buscar e manipular dados em um banco Relacional, é amplamente “simulada” sob outros formatos NoSQL, porque, no final do dia, SQL é uma das linguagens mais simples do universo!

Hoje em dia SQL é extremamente robusto: ele permite não só consultar e manipular dados, mas também permite fazer data wrangling de forma muito eficiente, fornece capacidade nativa para reconhecimento de padrões, expressões regulares, aprendizado de máquina, funções analíticas, e possui uma biblioteca de APIs bastante abrangente em todas as implementações de banco de dados.

A Força Bruta de Consistência

Outra característica marcante nos sistemas Relacionais é a INTEGRIDADE. Quando o objetivo é integridade, nada construído até hoje é mais rápido e mais simples do que o sistema de banco de dados Relacional. Há quase 40 anos ele tem sido o padrão para armazenamento na maioria dos sistemas de informação, porque a maioria dos sistemas precisa de integridade.

As propridades ACID [Atomicidade, Consistência, Isolamento e Durabilidade] são os fundamentos da integridade nos sistemas Relacionais, e ao lado da linguagem SQL, são vistas como as principais características deste modelo de persistência.

ATOMICIDADE: se uma transação tem vários comandos, ou faz tudo, ou não faz nada; CONSISTÊNCIA: a transação respeita a unicidade da chave primária, o valor que não pode ser nulo, a chave estrangeira, os datatypes e quaisquer outras regras definidas na tabela; ISOLAMENTO: uma transação não enxerga a outra que atua no mesmo dado. Um produto tem 1 unidade e duas compras são realizadas ao mesmo tempo: uma deve executar primeiro. Se a primeira efetivar, a segunda não consegue comprar o produto [por falta de estoque]. Se a primeira falhar, a segunda efetiva a compra do produto; DURABILIDADE: o dado alterado por uma transação persiste em disco, e este sempre será o mesmo até que outra transação válida o altere.

Para garantir a integridade em transações distribuídas, os sistemas Relacionais utilizam o protocolo Two-Phase Commit, conhecido como 2PC, para garantir a atomicidade [A do ACID].

Quando uma transação é distribuída entre vários bancos de dados, quando um deles faz commit, todos votam, e caso todos votem ‘sim’, eles registram o commit em logs locais – ou rollback, caso pelo menos um vote ‘não’, ou haja qualquer falha [fase 1]. Supondo que todos votem ‘sim’, a confirmação é retornada para todos, e a transação é efetivada em todos os bancos de dados [fase 2]. O log de confirmação local garante que todos podem exercer o commit, caso haja uma falha durante fase 2.

O modelo relacional é schema-full. Isto significa que a estrutura das tabelas [colunas, datatypes e constraints] precisa estar definida antes dos dados serem gravados. É como um contrato entre quem vai ler e quem escrever no banco de dados.

A característica schema-full, as propriedades ACID, e o protocolo 2PC são os alicerces da integridade no sistema de banco de dados Relacional. Há outros acessórios [como as leituras consistentes e o MVCC] para melhorar a experiência do usuário diante da força bruta de consistência disponível.

Há Certas Coisas que os Sistemas Relacionais Não Fazem por Você

Os TRADE-OFFS mais importantes dos sistemas Relacionais são, em primeiro lugar, A FALTA DE FLEXIBILIDADE DO FORMATO DE DADOS, e depois, A BAIXA CAPACIDADE DE ESCALAR no nível da internet.

A FALTA DE FLEXIBILIDADE foi na verdade uma vantagem do modelo Relacional nos anos 80-90 [quando os desenvolvedores tinham que fazer o schema na mão]: o modelo de dados é schema-full. Isto é, primeiro é necessário criar a estrutura dos dados, para depois inserí-los, e não o oposto [como ocorrem com os NoSQL]. Há vantagens na abordagem schemaless, principalmente nos tempos atuais, e portanto, hoje, não tê-la é um ponto negativo [mais adiante eu falo sobre Multi-Model, que torna o sistema Relacional mais moderno].

A BAIXA CAPACIDADE DE ESCALAR ocorre porque, em geral, nos sistemas Relacionais, os dados das tabelas não são distribuídos entre servidores distintos e independentes [shared-nothing], e por isso eles apenas escalam verticalmente [até a capacidade de um servidor, e não de vários] – esse é um forte limitador de escalabilidade.

Há, entretanto, uma implementação de software ainda única, da Oracle [chamada Oracle RAC], que permite que vários servidores ativos e distintos acessem os arquivos de um mesmo banco de dados [shared-disk], mantendo a consistência forte. No teorema CAP que explico mais adiante, o RAC recebe a classificação CA [consistency e availability]: essa tecnologia é a que mais oferece escalabilidade para um sistema de banco de dados Relacional, mas ainda é inferior aos níveis de escalabilidade oferecidos pelos NoSQL.

VOCÊ DEVE CONSIDERAR O SISTEMA DE BANCO DE DADOS RELACIONAL PARA DADOS QUE PRECISAM DE INTEGRIDADE.

Os Sistemas NoSQL são como Albatrozes: Ágeis no Ar, mas Desajeitados em Terra

Apesar de tanta inovação e robustez para gerenciar dados, por causa da internet, o modelo de infraestrutura que só escala verticalmente [para cima], como ocorre com os bancos de dados Relacionais, demonstrou não atender a escalabilidade necessária para suportar aplicações web de OLTP intenso: milhões de usuários com demandas variáveis e imprevisíveis.

No ano 2000 surgiram as primeiras tecnologias NoSQL que ganharam escala. Fizeram muito sucesso como forma de persistência nas redes sociais, e começaram a ganhar espaço nas empresas.

Os bancos de dados NoSQL, de forma geral, são baseados em estruturas de dados schemaless, em arquitetura shared-nothing [totalmente distribuído, nada é compartilhado], e por isso conseguem escalar horizontalmente [para os lados] e armazenar qualquer estrutura de dados. Há muitas implementações de NoSQL, sendo que as principais são Chave-Valor, Documentos, Grafos e Orientado a Coluna.

A implementação Chave-Valor é indicada para leitura ou escrita intensiva de qualquer coisa, não importa o formato, desde que seja com o maior throughput possível. A implementação de Documentos é indicada para manipular informações que são agrupadas e relacionadas, como um catálogo de produtos, por exemplo. Grafos é indicada para dados altamente conectados, para encontrar conexões entre pessoas e coisas. Orientado a Coluna é um híbrido do formato linha e coluna, e é indicado para altos volumes de dados, em especial para escrita [não tanto para consulta].

Você precisa entender o Teorema CAP [Consistency, Availability, Partition Tolerance] e sua importância no mundo dos sistemas distribuídos. Ele prova que um sistema que distribui seus dados em servidores diferentes [sem compartilhar qualquer componente de infraestrutura], não pode ter disponibilidade e consistência ao mesmo tempo. No advento de uma falha na rede ou em um servidor qualquer, a CONSISTÊNCIA É GARANTIDA [letra C do CAP, onde um leitor enxerga todas as escritas completadas previamente], ou a DISPONIBILIDADE É GARANTIDA [letra A do CAP, onde o sistema sempre estará disponível para leitura/escrita], e não ambos.

Em geral, os sistemas NoSQL suportam AP [A de Availability, e P de Partition Tolerance]: sempre que há escrita em um servidor, ela é replicada de forma assíncrona para outros servidores espelho para manter a disponibilidade da informação – todos os servidores, os que escrevem, e os que recebem as escritas replicadas, ficam disponíveis para leitura.

Como exemplo, em uma configuração de cluster com 10 servidores, em geral 5 permitem escrita, e os outros 5 permitem apenas leitura. Nesta configuração, cada servidor-escritor replica de forma assíncrona para seu par que só permite leitura. Cada conjunto escritor/leitores são completamente independentes de outros conjuntos escritor/leitores, e cada um desses conjuntos armazena uma parte da informação.

Se houver falha em um servidor, os demais servidores espelho continuam lendo ou escrevendo, mesmo que possa haver inconsistência: a falha impede que um servidor replique seus dados para as outros servidores espelho. Desta forma, quando se lê um dado nesta situação, ele estará eventualmente consistente. Isso ocorre porque o dado poderá ter sido alterado, mas esta alteração pode não ter sido propagada para as réplicas. Além disso, mesmo sem uma falha, como as replicações são assíncronas, é possível que uma leitura em uma réplica possa não estar enxergando a versão mais recente da informação. Logo, haveria também uma leitura eventualmente consistente.

Ao contrário dos sistemas AP, os sistemas CP privilegiam a consistência forte. Um servidor-escritor envia os dados de forma síncrona para os seus respectivos servidores espelho. Então, se você está lendo a partir do servidor que escreve, ou da réplica, você sempre estará lendo a informação mais recente. Isso é consistência forte. Entretanto, se um servidor que escreve tem uma falha e fica indisponível, os seus pares ficam impossibilitados de escrever para evitar um cenário de inconsistência. Por isso, uma parte da informação torna-se inacessível, porém não o sistema todo: apenas os servidores com falha.

Esse é o trade-off entre AP e CP. E não é possível um sistema de banco de dados ter C, A e P ao mesmo tempo, conforme prova o teorema.

Tanto os sistemas AP, como os CP, dizem ter Consistência. Mas é importante entender que existem dois tipos de Consistência: a Forte, onde um leitor enxerga todas as escritas feitas previamente; e a Eventual, onde um leitor pode ou não, isto é, eventualmente, enxergar as escritas feitas previamente. Além disso, existe a Consistência no ACID, que tem a ver com integridade do dado escrito [datatypes, null ou not null, constraints, etc], e também existe a Consistência no CAP, que indica se a informação que um leitor lê é, ou não, a versão mais recente.

Consistência eventual para as redes sociais, ok! Para os batches… humm, talvez. Para as aplicações online? Complicado…! Neste caso, se necessário, o desenvolvedor que deve garantir a consistência forte em um sistema AP, já que ela não está disponível nesse tipo de banco de dados – e vale lembrar que é muito complexo codificar consistência: não é exatamente para qualquer um! É uma codificação altamente suscetível a bugs [lembra quando falei sobre as inovações do sistema Relacional? Os NoSQL descartam várias delas, a consistência forte é um exemplo].

Quanto mais os bancos de dados NoSQL se aproximam das aplicações online nas empresas, maior é a necessidade de transações, ACID, e consistência forte.

Não é exatamente uma desilução dos NoSQL que suportam AP, pois eles ainda têm seu lugar em diversos casos de uso. Mas está cada vez mais comum a introdução de capacidades CP [consistência] nas tecnologias que outrora iniciaram sua implementação com AP.

Um outro ponto relevante é que nenhum sistema garante efetivamente 100% de disponibilidade [o A do CAP]. Na prática há alguns 9s de disponibilidade, mas nunca 100% [você pode ter 20 réplicas, mas embora difícil, não é impossível perder todas elas]. Então o A do CAP é apenas “teórico”, mesmo para os NoSQL AP, que notadamente sacrificam a consistência para supostamente garantir 100% da disponibilidade. De fato, tanto a consistência quanto a disponibilidade são sacrificadas nos sistemas NoSQL AP.

E para complicar um pouco mais, AP sempre sacrifica a consistência, pois em virtude da necessidade de baixa latência [lê-se replicação assíncrona], os dados em geral sempre estarão eventualmente consistentes, mesmo sem uma falha ou falta de comunicação na rede.

VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS NOSQL QUANDO ESCALABILIDADE FOR MUITO MAIS IMPORTANTE DO QUE INTEGRIDADE, DO CONTRÁRIO, CONSIDERE O RELACIONAL.

Obrigado pela Ajuda NoSQL: Agora é com a Gente!

A necessidade real nas empresas para atender as demandas de escalabilidade atuais é Consistência Forte [do SQL] com Escalabilidade Horizontal Distribuída [do NoSQL]. Eis então que surgem os bancos de dados NewSQL!

O título desta parte do meu artigo é originalmente do post de um blog do MemSQL, que faz uma sátira com os bancos de dados NoSQL, em favor do deles, um banco de dados NewSQL. E eles ainda completam: “Tá na hora de admitirmos o que todos nós já sabíamos por muito tempo: NoSQL é a ferramenta errada para muitos casos de usos nas aplicações modernas, e está na hora de seguirmos em frente.

O texto do post começa explicando a ascensão da tecnologia NoSQL diante das supostas limitações da tecnologia SQL para os sistemas mais modernos, digitais e cloud native. Na sequência é introduzida a tecnologia NewSQL, que emerge dos pontos positivos do SQL e NoSQL combinados, o que acaba por colocar em decadência as tecnologias só-NoSQL, e também só-SQL.

De fato, SQL fez emergir NoSQL, que fez emergir NewSQL. E os sistemas NewSQL são então, mais do que nunca, gratos pela contribuição dos NoSQL, que os fez surgir, daí o título ligeiramente escrachado do post.

A diferença mais notável entre um NoSQL e um NewSQL é que o último suporta consistência forte, e na melhor da boa vontade, SQL e outras características do sistema Relacional. Os sistemas de informação nas empresas não são Facebooks, Instagrams, Twitters. Elas precisam de consistência. Então sim, NewSQL ascende. NoSQL, decai.

Os sistemas NewSQL representam uma evolução em relação aos NoSQL, oferecendo suporte a CP do CAP. NewSQL tenta ser um SQL, e tolera partições de rede, a grande diferença. A tolerância a partição permite escalar horizontalmente, como os NoSQL, e entrega escalabilidade ao nível da internet.

Mas francamente, quase todos os NewSQL, ou todos realmente, não suportam SQL plenamente. Não há como ignorar quase 4 décadas de desenvolvimento. Todos os NewSQL suportam apenas uma porção do que os sistemas SQL tradicionalmente suportam: compliance ao ANSI plenamente, extensões proprietárias, ACID, 2PC, Multi-Model, segurança abrangente de dentro pra fora, backups e restores granulares, monitoração robusta com grande poder de instrumentação, e milhares de outras características.

É apreciável o esforço de construir uma consistência nativa bem elaborada numa arquitetura dominada por Albatrozes que voam bem, mas pousam terrivelmente mal [aqui eu me refiro aos NoSQL].

VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS NEWSQL QUANDO ESCALABILIDADE FOR MUITO RELEVANTE, TÃO QUANTO INTEGRIDADE, DO CONTRÁRIO, CONSIDERE ALGUM DOS ANTERIORES.

Não é um Pato, é Multi-Model

Os sistemas de banco de dados Multi-Model são aqueles que permitem nativamente vários formatos ao mesmo tempo, como Relacional, Grafos, Chave-valor, Documentos, Colunar e qualquer outro que se torne relevante.

A característica Multi-Model se torna relevante principalmente nos tempos atuais, onde as aplicações podem requerer persistência poliglota, isto é, um sistema de banco de dados diferente para cada parte da aplicação, já que cada um é melhor em algum caso específico.

A verdade é que sempre existe aquele sistema de banco de dados “cutting-edge“, de ponta, de última geração, crème de la crème. Aquele que só ele faz aquilo que ele faz. Mas o que também ocorre é que se aquilo que só ele faz se torna relevante, os sistemas de banco de dados multi-model o absorvem. Tem sido assim nos últimos anos, e provavelmente sempre será.

As inovações dos sistemas Single-Model são incorporadas nos sistemas Multi-Model

Desenvolver um banco de dados é muito complexo. Um exemplo disso é o bem difundido PostgreSQL [com suas limitações de escalabilidade], que fez por exemplo o Uber deixar de usá-lo, conforme mencionei no início deste artigo. É mais simples e rápido incorporar features novas do que construir todo um core, e é por isso que os sistemas de banco de dados Multi-Model ainda dominam.

VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS MULTI-MODEL QUANDO FLEXIBILIDADE DE SCHEMA E CONSISTÊNCIA FOREM AMBOS MUITO IMPORTANTES.