6.1 Batalha de abreviaturas: BASE vs. ÁCIDO
"Em química, o pH mede a acidez relativa de uma solução aquosa. A escala de pH vai de 0 (substâncias fortemente ácidas) a 14 (substâncias fortemente alcalinas); a água pura a 25°C tem um pH de 7 e é neutra. Os engenheiros de dados usaram essa metáfora para comparar bancos de dados em relação à confiabilidade das transações." Provavelmente, a ideia era esta: quanto maior o pH, ou seja, quanto mais próximo o banco de dados estiver de "alcalino" ("BASE"), menos confiáveis serão as transações. |
Bancos de dados relacionais populares, como o MySQL, surgiram apenas com base no ACID. Mas, nos últimos dez anos, os chamados bancos de dados NoSQL, que combinam vários tipos muito diferentes de bancos de dados com esse nome, se saíram muito bem sem o ACID. De fato, há um grande número de desenvolvedores que trabalham com bancos de dados NoSQL e não se importam com as transações e sua confiabilidade. Vamos ver se eles estão certos.
Você não pode falar em geral sobre o banco de dados NoSQL, porque é apenas uma boa abstração. Os bancos de dados NoSQL diferem entre si no design de subsistemas de armazenamento de dados e até mesmo em modelos de dados: NoSQL é CouchDB orientado a documentos e Neo4J gráfico. Mas se falarmos sobre eles no contexto de transações, todos eles tendem a ser semelhantes em uma coisa: eles fornecem versões limitadas de atomicidade e isolamento e, portanto, não fornecem garantias ACID. Para entender o que isso significa, vamos responder à pergunta: o que eles oferecem, senão ACID? Nada?
Na verdade. Afinal, eles, assim como os bancos de dados relacionais, também precisam se vender em um belo pacote. E eles criaram sua própria abreviatura "química" - BASE.
6.2 BASE como antagonista
E aqui novamente não irei por ordem de letras, mas começarei com o termo fundamental - consistência. Terei que nivelar seu efeito de reconhecimento, porque essa consistência tem pouco a ver com a consistência do ACID. O problema com o termo consistência é que ele é usado em muitos contextos. Mas essa consistência tem um contexto de uso muito mais amplo e, de fato, é exatamente essa consistência que é discutida quando se discute sistemas distribuídos.
Os bancos de dados relacionais sobre os quais falamos acima fornecem diferentes níveis de isolamento de transação, e o mais estrito deles garante que uma transação não possa ver alterações inválidas feitas por outra transação. Se você estiver no caixa de uma loja e nesse momento o dinheiro do aluguel for sacado da sua conta, mas a transação com a transferência do dinheiro do aluguel falhar e sua conta voltar ao valor anterior (o dinheiro é não debitado), então sua transação de pagamento no caixa não notará todos esses gestos - afinal, essa transação nunca foi concluída e, com base na exigência de isolamento da transação, suas alterações temporárias não podem ser percebidas por outras transações.
Muitos bancos de dados NoSQL abrem mão da garantia de isolamento e oferecem "consistência eventual" pela qual você eventualmente verá dados válidos, mas há uma chance de sua transação ler valores inválidos - ou seja, temporários, parcialmente atualizados ou desatualizados. É possível que os dados se tornem consistentes no modo "lazy" durante a leitura ("lazily at read time").
O NoSQL foi concebido como um banco de dados para análises em tempo real e, para obter maior velocidade, eles sacrificaram a consistência. E Eric Brewer, o mesmo que cunhou o termo BASE, formulou o chamado "teorema CAP", segundo o qual:
Para qualquer implementação de computação distribuída, é possível fornecer não mais do que duas das três propriedades a seguir:
- consistência de dados ( consistência ) - dados em nós diferentes (instâncias) não se contradizem;
- disponibilidade ( disponibilidade ) - qualquer solicitação a um sistema distribuído termina com uma resposta correta, mas sem garantia de que as respostas de todos os nós do sistema sejam as mesmas;
- tolerância à partição (tolerância à partição ) - Mesmo que não haja conexão entre os nós, eles continuam a funcionar independentemente um do outro.
Se você deseja uma explicação muito simples do CAP, aqui está.
Há opiniões de que o teorema CAP não funciona e geralmente é formulado de forma muito abstrata. De uma forma ou de outra, os bancos de dados NoSQL geralmente recusam a consistência no contexto do teorema CAP, que descreve a seguinte situação: os dados foram atualizados em um cluster com várias instâncias, mas as alterações ainda não foram sincronizadas em todas as instâncias. Lembre-se, mencionei o exemplo do DynamoDB acima, que me disse: suas alterações se tornaram duráveis - aqui está um HTTP 200 para você - mas só vi as alterações após 10 segundos? Outro exemplo do cotidiano de um desenvolvedor é o DNS, o sistema de nomes de domínio. Se alguém não souber, esse é exatamente o “dicionário” que traduz endereços http (s) em endereços IP.
O registro DNS atualizado é propagado para os servidores de acordo com as configurações do intervalo de cache - portanto, as atualizações não são percebidas imediatamente. Bem, uma inconsistência temporal semelhante (ou seja, eventualmente consistência) pode acontecer a um cluster de banco de dados relacional (digamos, MySQL) - afinal, essa consistência não tem nada a ver com a consistência do ACID. Portanto, é importante entender que, nesse sentido, é improvável que bancos de dados SQL e NoSQL sejam muito diferentes quando se trata de várias instâncias em um cluster.
Além disso, a consistência ponta a ponta pode significar que as requisições de escrita serão feitas fora de ordem: ou seja, todos os dados serão escritos, mas o valor que eventualmente será recebido não será o último da fila de escrita.
Os bancos de dados NoSQL não ACID têm o chamado “estado suave” devido ao modelo de consistência de ponta a ponta, o que significa que o estado do sistema pode mudar com o tempo, mesmo sem entrada. Mas tais sistemas se esforçam para fornecer maior acessibilidade. Fornecer 100% de disponibilidade não é uma tarefa trivial, por isso estamos falando de “disponibilidade básica”. E juntos esses três conceitos: “basicamente disponível”, “estado suave” (“estado suave”) e “consistência eventual” formam a sigla BASE.
Para ser sincero, o conceito de BASE me parece um invólucro de marketing mais vazio do que o ACID - porque não oferece nada de novo e não caracteriza o banco de dados de forma alguma. E anexar rótulos (ACID, BASE, CAP) a certos bancos de dados só pode confundir os desenvolvedores. De qualquer forma, decidi apresentar esse termo a você, porque é difícil ignorá-lo ao estudar o banco de dados, mas agora que você sabe o que é, quero que o esqueça o mais rápido possível. E vamos voltar ao conceito de isolamento.
6.3 Então os bancos de dados BASE não atendem aos critérios ACID?
Basicamente, onde os bancos de dados ACID diferem dos não ACIDs é que os não ACIDs realmente renunciam ao isolamento. Isso é importante entender. Mas é ainda mais importante ler a documentação do banco de dados e testá-los da maneira que os caras do projeto Hermitage fazem. Não é tão importante como exatamente os criadores deste ou daquele banco de dados chamam sua ideia - ACID ou BASE, CAP ou não CAP. O importante é o que exatamente este ou aquele banco de dados fornece.
Se os criadores do banco de dados afirmam que ele fornece garantias ACID, provavelmente há uma razão para isso, mas é aconselhável testá-lo você mesmo para entender se é assim e em que medida. Se eles declararem que seu banco de dados não oferece tais garantias, isso pode significar o seguinte:
-
O banco de dados não oferece nenhuma garantia de atomicidade. Enquanto alguns bancos de dados NoSQL oferecem uma API separada para operações atômicas (por exemplo, DynamoDB);
- O banco de dados não fornece garantia de isolamento. Isso pode significar, por exemplo, que o banco de dados não gravará os dados na ordem em que foram gravados.
Quanto à garantia de durabilidade, muitos bancos de dados se comprometem nesse ponto em prol do desempenho. A gravação em disco é uma operação muito longa e há várias maneiras de resolver esse problema. Não quero entrar muito na teoria do banco de dados, mas para que você entenda mais ou menos para onde olhar, descreverei em termos gerais como diferentes bancos de dados resolvem o problema de durabilidade.
Para comparar diferentes bancos de dados, entre outras coisas, você precisa saber quais estruturas de dados fundamentam o armazenamento de dados e o subsistema de recuperação de um determinado banco de dados. Resumindo: diferentes bancos de dados têm diferentes implementações de indexação - ou seja, organização do acesso aos dados. Alguns deles permitem que você grave dados mais rapidamente, outros - mais rápido para lê-los. Mas não se pode dizer em geral que algumas estruturas de dados tornam a durabilidade maior ou menor.
6.4 como diferentes bancos de dados indexam dados e como isso afeta a durabilidade e muito mais
Existem duas abordagens principais para armazenar e recuperar dados.
A maneira mais fácil de salvar dados é adicionar operações ao final do arquivo de maneira semelhante a um log (ou seja, sempre ocorre uma operação de anexação): não importa se queremos adicionar, alterar ou excluir dados - tudo As operações CRUD são simplesmente gravadas no log. Pesquisar o log é ineficiente e é aí que entra o índice - uma estrutura de dados especial que armazena metadados sobre exatamente onde os dados são armazenados. A estratégia de indexação mais simples para logs é um mapa de hash que rastreia chaves e valores. Os valores serão referências ao byte offset para os dados escritos dentro do arquivo, que é o log (log) e fica armazenado em disco. Essa estrutura de dados é armazenada inteiramente na memória, enquanto os próprios dados estão no disco e é chamada de árvore LSM (log estruturado merge).
Você provavelmente se perguntou: se escrevermos nossas operações no diário o tempo todo, ele crescerá exorbitantemente? Sim, e por isso foi inventada a técnica de compactação, que “limpa” os dados com alguma periodicidade, ou seja, deixa apenas o valor mais relevante para cada chave, ou apaga. E se tivermos mais de um log no disco, mas vários, e todos eles estiverem classificados, obteremos uma nova estrutura de dados chamada SSTable (“tabela de strings classificadas”), e isso sem dúvida melhorará nosso desempenho. Se quisermos classificar na memória, obteremos uma estrutura semelhante - a chamada MemTable, mas com ela o problema é que, se ocorrer uma falha fatal no banco de dados, os dados gravados por último (localizados na MemTable, mas ainda não gravados em disco) são perdidos. Na verdade,
Outra abordagem para indexação é baseada em B-trees (“B-trees”). Em uma árvore B, os dados são gravados no disco em páginas de tamanho fixo. Esses blocos de dados geralmente têm cerca de 4 KB de tamanho e têm pares chave-valor classificados por chave. Um nó de árvore B é como uma matriz com links para um intervalo de páginas. máx. o número de links em uma matriz é chamado de fator de ramificação. Cada intervalo de páginas é outro nó da árvore B com links para outros intervalos de páginas.
Eventualmente, no nível da folha, você encontrará páginas individuais. Essa ideia é semelhante a ponteiros em linguagens de programação de baixo nível, exceto que essas referências de página são armazenadas no disco e não na memória. Quando INSERTs e DELETEs ocorrem no banco de dados, algum nó pode se dividir em duas subárvores para corresponder ao fator de ramificação. Se o banco de dados falhar por qualquer motivo no meio do processo, a integridade dos dados pode ser comprometida. Para evitar que isso aconteça, os bancos de dados que usam árvores B mantêm um "log write-ahead", ou WAL, no qual cada transação é registrada. Este WAL é usado para restaurar o estado da árvore B se estiver corrompido. E parece que é isso que torna os bancos de dados que usam árvores B melhores em termos de durabilidade. Mas os bancos de dados baseados em LSM também podem manter um arquivo que executa essencialmente a mesma função do WAL. Portanto, vou repetir o que já disse, e talvez mais de uma vez: entenda os mecanismos de funcionamento do banco de dados que você escolheu.
O que é certo sobre as árvores B, no entanto, é que elas são boas para a transacionalidade: cada chave ocorre em apenas um lugar no índice, enquanto os subsistemas de armazenamento com diário podem ter várias cópias da mesma chave em diferentes shards (por exemplo, até que o a próxima compactação é realizada).
No entanto, o design do índice afeta diretamente o desempenho do banco de dados. Com uma árvore LSM, as gravações no disco são sequenciais e as árvores B causam vários acessos aleatórios ao disco; portanto, as operações de gravação são mais rápidas com o LSM do que com as árvores B. A diferença é especialmente significativa para unidades de disco rígido magnéticas (HDDs), onde gravações sequenciais são muito mais rápidas do que gravações aleatórias. A leitura é mais lenta em árvores LSM porque você precisa examinar várias estruturas de dados diferentes e tabelas SS que estão em diferentes estágios de compactação. Com mais detalhes, parece com isso. Se fizermos uma simples consulta de banco de dados com o LSM, primeiro procuraremos a chave na MemTable. Se não estiver lá, olhamos para o SSTable mais recente; se não estiver lá, veremos a penúltima SSTable e assim por diante. Se a chave solicitada não existir, então com o LSM saberemos isso por último. As árvores LSM são usadas, por exemplo: LevelDB, RocksDB, Cassandra e HBase.
Descrevo tudo com tantos detalhes para que você entenda que, ao escolher um banco de dados, você precisa considerar muitas coisas diferentes: por exemplo, você espera gravar ou ler mais dados. E ainda não mencionei a diferença nos modelos de dados (você precisa percorrer os dados, como o modelo gráfico permite? Existe alguma relação entre diferentes unidades em seus dados - então os bancos de dados relacionais virão em socorro?), e 2 tipos de esquemas de dados - ao escrever (como em muitos NoSQL) e ler (como em relacional).
Se voltarmos ao aspecto da durabilidade, a conclusão será a seguinte: qualquer banco de dados que grave em disco, independentemente dos mecanismos de indexação, pode fornecer boas garantias para a durabilidade de seus dados, mas você precisa lidar com cada banco de dados específico , o que exatamente ele oferece.
6.5 Como funcionam os bancos de dados na memória
A propósito, além dos bancos de dados que gravam em disco, também existem os chamados bancos de dados "na memória" que funcionam principalmente com RAM. Em suma, os bancos de dados na memória geralmente oferecem menor durabilidade para obter velocidades de gravação e leitura mais rápidas, mas isso pode ser apropriado para alguns aplicativos.
O fato é que a memória RAM há muito é mais cara que os discos, mas recentemente começou a ficar mais barata rapidamente, o que deu origem a um novo tipo de banco de dados - o que é lógico, dada a velocidade de leitura e gravação de dados da RAM. Mas você certamente perguntará: e quanto à segurança dos dados desses bancos de dados? Aqui, novamente, você precisa examinar os detalhes da implementação. Em geral, os desenvolvedores de tais bancos de dados oferecem os seguintes mecanismos:
- Você pode usar RAM alimentado por baterias;
- É possível gravar logs de alterações em disco (algo como os WALs mencionados acima), mas não os dados em si;
- Você pode gravar periodicamente cópias do estado do banco de dados em disco (o que, sem o uso de outras opções, não oferece garantia, mas apenas melhora a durabilidade);
- Você pode replicar o estado da RAM para outras máquinas.
Por exemplo, o banco de dados Redis na memória, que é usado principalmente como uma fila ou cache de mensagens, carece de durabilidade do ACID: ele não garante que um comando executado com sucesso será armazenado no disco, pois o Redis libera os dados no disco (se você ter persistência habilitada) apenas de forma assíncrona, em intervalos regulares.
No entanto, isso não é crítico para todos os aplicativos: encontrei um exemplo do editor online cooperativo EtherPad, que era liberado a cada 1-2 segundos e, potencialmente, o usuário poderia perder algumas letras ou uma palavra, o que dificilmente era crítico. Caso contrário, como os bancos de dados na memória são bons porque fornecem modelos de dados que seriam difíceis de implementar com índices de disco, o Redis pode ser usado para implementar transações - sua fila de prioridade permite que você faça isso.
GO TO FULL VERSION