Elasticsearch como um banco de dados NoSQL
ATUALIZAÇÃO: este artigo se refere à nossa oferta hospedada do Elasticsearch com um nome mais antigo: Found. Observe que o Found agora é conhecido como Elastic Cloud. As avaliações sem custo hospedadas de 14 dias do Elasticsearch estão disponíveis no Elastic Cloud.
O Elasticsearch pode ser usado como um banco de dados “NoSQL”? NoSQL significa coisas diferentes em contextos diferentes e, curiosamente, não se trata realmente de SQL. Começaremos com “Talvez!” e examinaremos as várias propriedades do Elasticsearch, bem como aquelas que ele sacrificou a fim de se tornar um dos mecanismos de busca e analítica mais flexíveis, escaláveis e eficientes até agora.
Afinal, o que é um banco de dados NoSQL?
O NoSQL-database define o NoSQL como “Bancos de dados de próxima geração principalmente abordando alguns destes pontos: ser não relacional, distribuído, open source e escalável horizontalmente.” Em outras palavras, não é uma definição muito precisa.
Não se trata de SQL em particular. Por exemplo, a linguagem de consulta do Hive é claramente inspirada no SQL. O mesmo vale para a linguagem de consulta do Esper, que opera em fluxos em vez de relações. Além disso, você sabia que antigamente o PostgreSQL se chamava “Postgres” e tinha “Quel” como sua linguagem de consulta? Embora seja antes de tudo um ORDBMS, ele agora também tem muitos recursos para torná-lo viável como um armazenamento de documentos sem esquema.
Não se trata de ACID também. O Hyperdex é um exemplo de banco de dados NoSQL que visa fornecer transações ACID. O MySQL, certamente um banco de dados SQL, tem um histórico de interpretações duvidosas do que o ACID realmente significa.
Relações? Embora a maioria dos bancos de dados NoSQL não ofereça suporte para junção no mesmo sentido que os bancos de dados relacionais tradicionais e deixe isso como um exercício para o usuário, existem aqueles que o fazem. RethinkDB, Hive e Pig, para citar alguns. Neo4j, um banco de dados orientado a grafos, certamente lida com relações — é excelente para percorrer relações (ou seja, bordas) em grafos. O Elasticsearch tem um conceito de junção de “tempo de consulta” com relações pai/filho e junção de “tempo de índice” com tipos aninhados.
Distribuído? Embora existam alguns bancos de dados SQL distribuídos por aí e alguns projetos almejando ser algo como um NoSQLite, bancos de dados de geração mais recente tendem a ser distribuídos de uma forma ou de outra.
Para resumir, não faz sentido definir com precisão o NoSQL nem simplesmente dizer que o Elasticsearch é um banco de dados NoSQL do tipo “armazenamento de documentos”. No momento em que escrevo, o nosql-database.org lista mais de 20 deles.
Nas próximas seções, veremos algumas propriedades importantes e como o Elasticsearch as implementa ou não.
Sem transações
O Lucene, sobre o qual o Elasticsearch foi construído, tem uma noção de transações. Por outro lado, o Elasticsearch não tem transações no sentido típico. Não há como reverter um documento enviado, e você não pode enviar um grupo de documentos e ter todos ou nenhum deles indexados. O que ele tem, no entanto, é um write-ahead-log para garantir a durabilidade das operações sem ter de fazer um caro commit do Lucene. Você também pode especificar o nível de consistência das operações de índice, em termos de quantas réplicas devem reconhecer a operação antes de retornar. O padrão é um quórum, ou seja, \(\lfloor\frac{n}{2}\rfloor + 1\).
A visibilidade das alterações é controlada quando um índice é atualizado, que, por padrão, ocorre uma vez por segundo e a cada shard.
O controle de simultaneidade otimista é feito especificando a versão dos documentos enviados.
O Elasticsearch foi desenvolvido para ser rápido. Fazer transações distribuídas é muito trabalho. Não fornecê-las torna muitas coisas mais fáceis. Ao aceitar que o que lemos pode ser um tanto obsoleto e que todos veem a mesma linha do tempo, o Elasticsearch pode servir muitas coisas dos caches — o que é fundamental para o desempenho que o faz ser tão amado.
Flexibilidade para esquema
O Elasticsearch não exige que você especifique um esquema antecipadamente. Jogue um documento JSON nele e ele fará algumas suposições para inferir seu tipo. Ele faz um bom trabalho em coisas como números, boolianos e carimbos de data/hora. Para strings, ele usa o analisador “padrão”, que geralmente é bom para começar.
Embora seja indiscutivelmente “livre de esquema”, no sentido de que você não tem de especificar um esquema, gostamos de pensar nele como “flexível para esquema”. Para desenvolver uma ótima busca e/ou analítica, você realmente precisa ajustar seus esquemas. O Elasticsearch tem um amplo conjunto de ferramentas poderosas para ajudar, como modelos dinâmicos, objetos multicampo etc. Isso é abordado com mais detalhes em nosso artigo sobre mapeamento.
Relações e restrições
O Elasticsearch é um banco de dados orientado a documentos. Todo o grafo de objetos que você deseja buscar precisa ser indexado, portanto, antes de indexar seus documentos, eles devem ser desnormalizados. A desnormalização aumenta o desempenho da recuperação (já que nenhuma junção de consulta é necessária), usa mais espaço (porque o conteúdo precisa ser armazenado várias vezes), mas torna mais difícil manter o conteúdo consistente e atualizado (já que qualquer alteração precisa ser aplicada a todas as instâncias). No entanto, é excelente para cargas de trabalho write-once-read-many.
Por exemplo, digamos que você configurou um banco de dados contendo clientes, pedidos e produtos e deseja buscar pedidos com o nome de um produto e um usuário. Isso poderia ser resolvido indexando os pedidos com todas as informações necessárias sobre o usuário e os produtos. A busca se torna fácil, mas o que acontece quando você deseja alterar o nome do produto? Em um design relacional com normalização adequada, você simplesmente atualizaria o produto e pronto. É nisso que ele é realmente bom. Com um banco de dados de documentos desnormalizados, todo pedido com o produto teria de ser atualizado.
Em outras palavras, com bancos de dados orientados a documentos como o Elasticsearch, projetamos nossos mapeamentos e armazenamos nossos documentos de forma que sejam otimizados para busca e recuperação.
Conforme mencionamos na introdução, o Elasticsearch tem um conceito de junção de “tempo de consulta” com relações pai/filho e junção de “tempo de índice” com tipos aninhados. Provavelmente abordaremos isso com mais profundidade em um artigo futuro. Enquanto isso, podemos recomendar a apresentação de Martijn van Groningen “Document relations with Elasticsearch” (Relações de documentos com o Elasticsearch).
A maioria dos bancos de dados relacionais também permite especificar restrições para definir o que é e o que não é consistente. Por exemplo, integridade referencial e exclusividade podem ser impostas. Você pode exigir que a soma dos movimentos da conta seja positiva e assim por diante. Bancos de dados orientados a documentos tendem a não fazer isso, e o Elasticsearch não é diferente.
Robustez
Um banco de dados deve ser robusto, especialmente se é seu sistema oficial de registro. Idealmente, deve ser possível cancelar uma consulta cara, e você certamente não quer que o banco de dados pare de funcionar, a menos que você o instrua a fazê-lo.
Infelizmente, o Elasticsearch (e os componentes de que ele é feito) atualmente não lida muito bem com erros de OutOfMemory. Abordamos isso com mais detalhes em Elasticsearch em produção, falhas causadas por falta de memória. É muito importante fornecer ao Elasticsearch memória suficiente e ter cuidado antes de executar buscas com requisitos de memória desconhecidos em um cluster de produção.
Embora seja provável que isso melhore com o amadurecimento do Elasticsearch, é importante lembrar que o Elasticsearch foi desenvolvido para velocidade, pressupondo que a memória seja abundante.
Distribuído
Veja também: Elasticsearch em produção, rede.
Antes de criar o Elasticsearch, Shay Banon trabalhava no Compass. Percebendo que seria difícil transformá-lo em um mecanismo de busca distribuído, ele começou do zero e criou o Elasticsearch1. O Elasticsearch foi projetado para ser distribuído e fácil de escalar horizontalmente (scale-out) para lidar com grandes quantidades de dados em hardware comum.
O Elasticsearch é incrivelmente fácil de começar a usar para um sistema distribuído, mas os sistemas distribuídos são complicados. Falamos um pouco mais sobre isso em Elasticsearch em produção, rede, portanto, o que se segue é um breve resumo.
A própria natureza de um sistema distribuído implica uma variedade de coisas que podem dar errado. Como tal, diferentes sistemas de banco de dados voltam-se para diferentes pontos fortes: alguns primam por fortes garantias, outros por estarem sempre disponíveis, apesar de serem errôneos mesmo em algumas (ou até na maior parte) das vezes. Além disso, o que um sistema de banco de dados afirma alcançar quando ocorrem problemas raramente é o que ele realmente enfrenta, como Kyle Kingsbury explora em sua excelente série sobre os perigos das partições de rede. Resumindo, ele descobre que, embora o banco de dados distribuído funcione bem em um dia bom, a maioria sofre quando submetida à grande quantidade de possíveis maneiras de falhar.
Em termos de consistência, disponibilidade e tolerância a partições, o Elasticsearch é um sistema CP, para uma definição bastante fraca de “consistente” (consistente, mas não disponível sob partições de rede). Se você tem uma carga de trabalho somente leitura, o Elasticsearch permite que você alcance um comportamento AP (disponível, mas não consistente sob partições de rede) por ter um requisito de “nós master mínimos” relaxado, ou seja, não requer um quórum. Geralmente, no entanto, você precisará que a maioria dos nós no cluster esteja disponível. Gravar em um cluster mal configurado sem essa maioria, ou seja, um cluster com um “cérebro dividido”, pode resultar em uma perda de dados irrecuperável. Isso não é específico do Elasticsearch.
Em termos de redimensionamento, um índice é dividido em um ou mais shards. Isso é especificado quando o índice é criado e não pode ser alterado. Assim, um índice deve ter shards em quantidade proporcional ao crescimento previsto. À medida que mais nós são adicionados a um cluster do Elasticsearch, ele faz um bom trabalho na realocação e na movimentação dos shards. Como tal, o scale-out do Elasticsearch é muito fácil.
Segurança
Veja também: Elasticsearch em produção, segurança.
O Elasticsearch não tem nenhum recurso para autenticação ou autorização. Você deve considerar qualquer pessoa que possa se conectar ao seu cluster do Elasticsearch como tendo direitos de “superusuário”, especialmente se as poderosas funcionalidades de script do Elasticsearch estiverem habilitadas.
Resumo
Certamente é possível usar o Elasticsearch como um armazenamento principal, quando as limitações descritas não são impeditivas. Um bom exemplo é ao usar o Logstash. O Logstash é uma ferramenta fantástica para gerenciar logs e colocá-los no Elasticsearch, e talvez também arquivá-los em outro lugar, por precaução. Os logs são gravados uma vez e lidos muitas vezes. Sem atualização, sem necessidade de transações, sem restrições de integridade etc.
E quanto a sistemas como o Postgres, que vêm com busca de texto completo e transações ACID? (Outros exemplos são as funcionalidades de texto completo do MySQL, MongoDB, Riak etc.) Embora você possa implementar uma busca básica com o Postgres, há uma grande lacuna no desempenho possível e nos recursos. Conforme mencionamos na seção sobre transações, o Elasticsearch pode “trapacear' e fazer muito armazenamento em cache, sem se preocupar com o controle de simultaneidade multiversão e outras coisas complicadas. A busca também é mais do que encontrar uma palavra-chave em um texto: trata-se de aplicar o conhecimento específico do domínio para implementar bons modelos de relevância, fornecendo uma visão geral de todo o espaço de resultados e oferecendo recursos como verificação ortográfica e preenchimento automático. Tudo isso com rapidez.
O Elasticsearch é comumente usado além de outro banco de dados. Um sistema de banco de dados com foco mais forte em restrições, correção e robustez, e em ser prontamente atualizável de forma transacional, tem o registro mestre — que é então enviado de forma assíncrona para o Elasticsearch. (Ou puxado, se você usar um dos “rios” do Elasticsearch.) Manter a sincronização é um tópico que abordaremos em detalhes em um artigo futuro. Aqui no Found, normalmente usamos o PostgreSQL e o ZooKeeper como guardiões das verdades, que alimentamos no Elasticsearch para oferecer uma busca incrível.
Como com tudo o mais, não há bala de prata, não há um banco de dados para a todos governar. É provável que sempre assim, então conheça os pontos fortes e fracos dos seus armazenamentos!
Referências
Banon, Shay: The Future of Compass & Elasticsearch (O futuro do Compass e do Elasticsearch) — https://thedudeabides.com/articles/the_future_of_compass
- Shay Banon, The future of compass & elasticSearch — https://thedudeabides.com/articles/the_future_of_compass.↩