Devo usar NoSQL e MongoDB?

Por -

A ideia desse post é condensar os pontos que podem levar a decisão de utilizar uma tecnologia NoSQL em uma aplicação web. Vamos dar uma atenção especial ao MongoDB, um dos banco de dados NoSQL mais populares do mercado. A motivação por trás desse post são as perguntas que tenho recebido frequentemente sobre o assunto. Percebo que as vezes não existe uma ideia muito clara sobre o porque usar NoSQL, mas a curiosidade despertada pelo "hype" pode ser útil.


TL; DR: NoSQL? Sim, deve. MongoDB? Talvez.

Devo usar NoSQL?

Para melhor entender a "ausência" de SQL, precisamos entender o que exatamente é o SQL. As primeiras noções de SQL foram descritas em um paper de 1970, enquanto em paralelo, o paradigma de programação com orientação a objetos só começou a ser divulgado em 1980. tendo o surgimento do C++ ("Evolução da linguagem C" com orientação a objetos) só ocorrido em 1983. Além disso, a internet nasceu (ainda que bem rústica nessa época) em meados dos anos 80.

Ou seja, SQL e banco de dados relacional é um conceito bem antigo, "pré orientação a objetos" e "pré internet".

Apesar de todo o hype recente em torno de NoSQL em geral, NoSQL é um termo bem difícil de definir e muitas vezes é mal interpretado. Not only SQL (NoSQL) é definido como Nova gereção de banco de dados comumente: não relacionais, distribuídos, de código aberto e escaláveis horizontalmente.

NoSQL Definition: Next Generation Databases mostly addressing some of the points: being non-relational, distributed, open-source and horizontally scalable. [...] schema-free, easy replication support, simple API, eventually consistent / BASE (not ACID), a huge amount of data and more.

-nosql-database.org

Ou seja, sistemas de armazenamento de dados que visam resolver problemas atuais como escalabilidade, velocidade, adaptabilidade e consistência.

NoSQL consiste em basicamente ir além dos conceitos descritos em 1970 e por isso pode ser mais eficiente em armazenar o que conhecemos hoje como objetos. Além disso, são eficientes também para dados que, mesmo não sendo objetos, não possuem uma natureza onde seja necessário normalizar os campos ("quebrar em tabelas").

NoSQL pode ser mais eficiente em armazenar objetos e dados que não precisam ser normalizados.

Performance de acesso

Memcached e Redis são exemplos de banco de dados NoSQL que praticamente toda a aplicação web precisa. Resumidamente, esses bancos de dados do tipo Key-value guardam dados que precisam ser acessados rapidamente e de forma direta como sessões de usuário, cache, fila de background jobs e outros.

Nesse tipo de banco de dados (Key-value) o acesso a um dado é extremamente rápido, por outro lado a chave primária é a unica forma de fazer uma consulta, por isso são adequados para dados que não precisam ser normalizados e que possuem uma chave primária bem definida.

Um case muito interessante é o do Instagram, que utiliza Redis extensivamente em seu serviço.

One simple solution to this problem would be to simply store them as a bunch of rows in a database, with “Media ID” and “User ID” columns. However, a SQL database seemed like overkill given that these IDs were never updated (only inserted), didn’t need to be transactional, and didn’t have any relations with other tables. Instead, we turned to Redis [...]

- Mike Krieger, Instagram co-founder

Vale mencionar que mesmo um case simples como um blog vai se beneficiar de usar um Key-value database para cache.

Performance e qualidade de consulta

A maioria dos banco de dados possuem uma velocidade consistente para consultas feitas utilizando índices. Porém isso começa a mudar conforme a falta de precisão e a subjetividade das consultas aumenta.

Se você já precisou usar o operador LIKE do SQL, você sabe do que estou falando. A qualidade e a performance (ao buscar de forma imprecisa e em campos onde não existe índice) começam a degradar conforme a quantidade de dados aumenta. Fica praticamente impossível "domar" os resultados de busca.

A estratégia para solucionar tal problema é a de ter um índice exclusivo para busca, e alimentar esse índice já tratando a forma com que as pessoas vão pesquisar, ou seja, fazer o "design do banco de dados" pensando na forma com que os dados vão ser acessados. Uma tecnica para isso é o "indice invertido".

Existem tecnologias específicas para isso (search engines). Listado na categoria Documento Store do nosql-database.org, o Elasticsearch é um banco de dados voltado para busca e análise, tendo como características ser distribuível, escalável horizontalmente e de alta disponibilidade.

O Elasticsearch é um exemplo de NoSQL que muitas aplicações web podem precisar. Não sendo tão essencial como um Key-value de acesso rápido, tecnologias como Elasticsearch dão mais poder a produtos que tem busca, análise de log ou análise de dados como uma das principais funcionalidades.

Como exemplo temos o case de Elasticsearch no Mercado Livre.

Elasticsearch's powerful search capabilities and fast response time empower sellers to conduct business, which directly impacts MercadoLibre's ability to generate revenue.

- Federico Ocampo, MercadoLibre's Project Leader

Outros tipos de NoSQL

Tentei ilustrar acima casos onde alguns tipos de bancos NoSQL do tipo Key-value e Document Store podem ser úteis. Porém a lista de tipos e finalidades de bancos de dados é extensa, contando com Wide Column Store, Multimodel, Object Databases, Grid, Multidimensional e ate mesmo algumas tecnologias listadas como uncategorized. Você pode encontrar a lista completa e a explicação de cada categoria em nosql-database.org.

Tudo parte do princípio que não existe bala de prata, e que é preciso estudar a melhor solução para cada problema a ser resolvido.

Devo usar MongoDB?

Diferente dos exemplos que mencionei acima, a proposta do MongoDB é servir como o data-storage primário da aplicação, ou seja, ser usado no lugar de um MySQL, PostgresSQL, SQLServer, Oracle Database e similares.

O que é o MongoDB?

MongoDB é um banco de dados NoSQL, que usa um modelo de dados flexível, de modo que o schema podem mudar facilmente conforme a aplicação evolui. Apesar de ser um banco de dados NoSQL ele oferece funcionalidades comuns dos bancos de dados tradicionais, tais como múltiplos índices, uma linguagem de consulta completa, operações de agregação e consistência rigorosa.

É exatamente essa proposta de oferecer as features de um bancos de dados "tradicional" que o torna, na minha opinião, uma das alternativas mais viáveis como data-storage primário NoSQL. (Porque a maioria dos bancos NoSQL não se preocupam em preencher todas as lacunas dos bancos que estamos acostumados).

Schema flexível

No MongoDB os dados são armazenados em JavaScript Object Notation (JSON), podendo assim conter atributos aninhados e evitar normalizações desnecessárias. Um exemplo seria guardar os endereços na coleção dos usuários, onde é possível fazer queries do tipo "todos os usuários que moram em uma cidade específica" sem usar JOIN:

// Record
db.users.insert({
  name: 'Kate Monster',
  email: 'kate_monster@example.com',
  addresses : [
     { street: '123 Sesame St', city: 'Anytown', cc: 'USA' },
     { street: '123 Avenue Q', city: 'New York', cc: 'USA' }
     // ... Any amount of addresses ;)
  ]
});

// Query
db.users.find(['addresses.city': 'New York']);

Escalabilidade

Por se tratar de um banco de dados NoSQL, MongoDB foi construído para escalabilidade, performance e alta disponibilidade, escalando de implementações simples para grandes e complexas arquiteturas (Ex: multi-site, multi-region, multi-tenacy) com replicação nativa e failover automatizado.

Se o responsável pelo schema do banco não souber o que esta fazendo, você pode acabar com o desempenho similar ou pior que o de um banco de dados relacional. Porém, fazendo direito, escalar horizontalmente não vai ser uma "gambiarra" ou precisar de um tool de "sharding" tipo o pg_shard do Postgres (que inevitavelmente mata o ACID).

Performance

A opção de usar o banco de dados in-memory (de forma semelhante ao Redis) da o benefício de ter alto desempenho para escritas. Diferente dos bancos de dados relacionais que obrigatoriamente escrevem os dados em disco antes de retornar o sucesso da operação.

Então resumidamente temos:

  • Schema flexível (Baseado em documentos)
  • Escalabilidade horizontal (Multi-Datacenter) nativa
  • Performance de escrita in-memory

Quando usar MongoDB?

The problem is not the relational databases, but when you use then for everything [...] One of the biggest handcaps that we had for a long time is this obsession in everything being stored in relational databases.

- Eric Evans on Domain-Driven Design at 10 Years - 47:21 (2015)

Quando os dados não se encaixam no modelo relacional

Dados que são muito complexos para modelar, onde os campos de uma entrada podem variar dependendo dos attributos da mesma, ou a necessidade de desnormaliza-los gravando dados serializados ou no formato JSON dentro de uma coluna, são fortes indícios de que seu projeto esta sofrendo com a escolha errada de utilizar um banco de dados relacional. Tais problemas indicam explicitamente que MongoDB seria mais adequado para o problema em questão.

Quando seus dados são na verdade objetos

Se sua aplicação lida exclusivamente com objetos, através de um ORM por exemplo. Quase todas as queries precisam acessar muitas tabelas para construir um objeto de domínio. Por fim, várias das tabelas que existem para compor esse objeto nunca vão ser acessadas diretamente e só existem por convenção (Aquela velha convenção dos anos 70 de normalizar tudo!). Com MongoDB, esses dados ficam todos no mesmo registro, podendo ser aninhados e agrupados em arrays.

Relational vs Document

Quando sua aplicação valida a consistência dos dados, não o banco

Antigamente as regras de negócio ficavam no banco de dados na forma de constraints porém, hoje em dia é mais comum e conveniente a implementação dessas regras de negócio no código da aplicação. O benefício é poder contar com testes automatizados, versionamento, manutenabilidade e critérios de validação complexos sobre os dados.

Se a sua aplicação tem a responsabilidade de validar os dados e a consistência antes de gravar um registro no banco, então MongoDB (onde não existem constraints) pode fazer sentido.

Quando o projeto da aplicação é orientado ao domínio

Para quem conhece Domain Driven Design (DDD). O próprio autor do DDD, Eric Evans, reforça que os banco de dados relacionais não são apropriados para armazenar objetos que mapeiam entidades de domínio. Muitas implementações de DDD acabam com value objects desnormalizados e serializados no banco de dados.

NoSQL is a great boom for DDD. [...] Data in relational database have to be structured in a certain way that in the days that the objects were dominant, the relational database were still the dominant database, so we have to use ORMs and the people would talk about the impedance mismatch [...] The fundamental conceptual estructure of an object is different from relational tables.

- Eric Evans on Domain-Driven Design at 10 Years - 47:21 (2015)

Quando seu projeto precisa se adaptar a mudanças

MongoDB pode impactar positivamente a produtividade em projetos onde o formato dos dados evolui ou muda facilmente. Pois o schema flexível do MongoDB permite que o formato dos documentos evoluam de uma forma progressiva. Não sendo necessário alterar tabelas ou executar migrações para adições nas entidades. O que torna o MongoDB uma opção muito interessante para startups e projetos com metodologias ágeis.

Ainda que hoje existam as migrações para ajudar modificar o schema de um banco de dados de forma mais rápida e evolutiva. É redundante fazer as modificações de campos na sua aplicação e depois na base de dados. Com MongoDB a declaração dos campos fica exclusivamente na sua aplicação, junto com as regras de negócio.

Na Leroy Merlin, o schema de determinadas entidades pode ser alterado pelos próprios usuários do sistema. Temos várias mudanças nos schema das mais de 1000 categorias de produtos diariamente. Isso não seria possível (pelo menos não em real-time) com ALTER TABLE em um banco relacional.

Quando a escalabilidade é importante

O MongoDB já fornece as ferramentas necessárias para fazer escritas com performance in-memory e para trabalhar com replicas e shards distribuídos.

Ainda que seja possível escalar com bancos de dados relacionais, fazer isso é mais custoso, complexo e instável. Sem falar que as estratégias para escalar banco de dados relacionais de forma distribuída comprometem a atomicidade, consistência e o isolamento.

Quando a sua equipe conhece MongoDB

Se a equipe tem alguma noção de MongoDB e de como modelar os dados de forma não relacional, então você tem o "sinal verde". Talvez esse seja o ponto definitivo (depois de se identificar com os itens anteriores da lista).

Se a equipe, que é proficiente em bases de dados relacionais, não tem nenhum conhecimento em MongoDB (nem disponibilidade para estudar), utilizar uma base de dados convencional (Ex: MySQL) ainda é uma melhor opção. Ainda que você abra mão dos benefícios de produtividade, manutenção, escalabilidade e performance de usar NoSQL como primary-storage, usar o MongoDB de forma inadequada pode gerar mais problemas do que benefícios. Muitos dos relátos ruins sobre MongoDB são por causa de uso incorreto.

Como segunda opção ao parágrafo anterior, treinar uma equipe para utilizar MongoDB pode ser uma boa opção. O MongoDB University oferece um curso online gratuito de 7 semanas que cobre mais do que o essencial para trabalhar com MongoDB. Eu fiz o curso e recomendo a todos que querem conhecer um banco de dados da nova geração.

Um padrão que observo é: As pessoas que conhecem bem como o MongoDB funciona (Ex: quem fez o curso do MongoDB University) normalmente enxergam ele como uma opção mais adequada e produtiva para a maioria das finalidades onde hoje utilizamos bancos de dados relacionais.

Quando inovação não é um problema

Usar banco de dados relacional "tradicional" para tentar resolver tudo é um dos conceitos mais difundidos do mundo do software. Não é da noite para o dia que vamos mudar o mindset dos arquitetos de software, analistas, desenvolvedores e stakeholders. Portanto é necessário ter certa abertura e "pensar fora da caixa" para usar MongoDB.

Ainda que existam benefícios e estabilidade comprovada, sempre haverá aqueles que preferem manter a forma antiga de se fazer as coisas.

Quando não usar MongoDB?

No final das contas, a principal coisa a entender sobre MongoDB é que ele não é uma silver bullet e, como todas as tecnologias, tem vantagens e desvantagens significativas. Existem diversos casos onde MongoDB não é adequado, vou tentar quebrar em simples tópicos para facilitar o entendimento.

Quando as vantagens não convencem

Se depois de tudo que você leu no tópico "Quando usar MongoDB?" você sente que MongoDB não é adequado ao seu projeto. Então ele provavelmente não é.

Quando você precisa de transactions e ACID

Quando transactions atômicas obrigatoriamente isoladas forem a unica forma de resolver o problema, MongoDB não é uma opção. Ainda que você precise comprometer a escalabilidade para isso.

Só para a informação, "fazer pedido" não requer uma transaction atômica isolada. Existem outras formas de resolver esse problema.

Quando MongoDB não é o suficiente

MongoDB é um banco de dados com uma proposta híbrida. Ele suporta índices secundários e queries complexas como bancos tradicionais. Ele tem Map/Reduce/Aggregation como Hadoop. Ele tem auto-sharding que funciona de forma parecida com algumas implementações de bancos Key-Value. Além disso ele possuí consistencia parecida com DynamoDB ou SimpleDB, com right concerns configuráveis (se a escrita vai para disco ou só para a memória antes de retornar "Ok"). Ele também possui funcionalidade de busca textual de índice invertido (semelhante ao Elasticsearch).

Porém em todos esses fatores, MongoDB pode ser superado por outras tecnologias. Conforme as necessidades evoluem, seu projeto pode chegar ao ponto onde vai precisar de ferramentas NoSQL mais específicas:

  • Se você executa muitas operacões de Map/Reduce, voce vai acabar usando Hadoop.
  • Se você utilizar sharding de forma pesada e só faz consultas Key-Value, então Riak KV pode ser uma opção interessante.
  • Se você se preocupa com uma possível escalabilidade massiva Cassandra pode ser uma melhor opção.
  • Se você usa MongoDB para cache, Redis e Memcached podem ser o suficiente.
  • Se você usa MongoDB para queues, você eventualmente vai evoluir para RabbitMQ, ZeroMQ, etc.
  • Se você usa MongoDB para busca, Elasticsearch, Solr ou Sphinx serão mais poderosos.

Muitos dos bancos mencionados acima são muito específicos no que eles se propõe a solucionar. MongoDB é menos específico mas serve para todas essas finalidades.

Portanto, conforme você chega a um nível elevado, MongoDB (ou qualquer banco relacional) vai se mostrar inferior a uma solução especializada. Por exemplo, na Leroy Merlin, houve a necessidade de utilizar Elasticsearch para ter uma funcionalidade de busca mais poderosa.

Conclusão

NoSQL é adequado a qualquer projeto de aplicação para a internet, trazendo benefícios de performance em cache, sessões de usuário, background-jobs, busca e outros. Mesmo um blog vai se beneficiar de um cache com Memcached ou Redis.

MongoDB pode trazer vários benefícios a longo prazo caso seja adequado ao projeto. Porém não se precipite ao optar por essa tecnologia. Certifique-se que a equipe de desenvolvedores conhece bem esse banco de dados e que o reconhecem como uma boa opção para o trabalho.

NoSQL adoption is inevitable because, just as in every other walk of life, there are different tools for different jobs.

- NoSQL: Not Going Anywhere For a While? - Stephen O'Grady (2009)

Referências