Minha experiência com MongoDB: erros, acertos e dicas

Um ano e meio atrás embarquei em um projeto que antes da minha entrada já havia adotado o MongoDB. Meu objetivo neste post é relatar alguns dos nossos erros e acertos.

O que deu certo

Não tivemos os problemas que lemos por aí como locks em bases de dados e o desempenho que obtivemos foi excelente. Montar um cluster com replicação de dados do tipo replica-set se mostrou um procedimento super tranquilo, assim como a configuração de sharding.

Se você tem estruturas de dados cujos atributos podem variar bastante de um elemento para outro em uma mesma coleção e não liga para redundância de informações, MongoDB se mostra uma solução muito interessante. Ele funciona.

Já sabia algum tempo atrás de algumas das suas limitações. É importante lembrar que limitação divulgada pelo fabricante não é defeito, mas sim característica. Uma limitação que surge “acidentalmente”, esta sim é um defeito. Aliás, na época cheguei a escrever sobre isto, alguns de vocês devem se lembrar. Aqueles pontos que falei em outubro de 2013 ainda se mantém (inclusive a versão em inglês deste site foi parar no Hacker News graças a este post).

Sobre desempenho a crítica que faço é sempre a mesma: benchmarks de internet não são válidos até que você tenha experiência no seu projeto. No nosso caso o que deu certo ocorreu por que satisfez dois requisitos.

  • As estruturas de dados tinham atributos que realmente variavam bastante. Algo com atributos fixos não seria adequado. Além disto documentos embarcados eram uma alternativa interessante: redundância de dados não era um problema.
  • Precisávamos de algo cujo tempo de escrita fosse o menor possível e sabíamos exatamente como estas estruturas deveriam se comportar.

Aonde estes dois requisitos se aplicavam, obtivemos sucesso.

E onde deu errado

Sabe estes dois requisitos que citei acima? São aonde vejo MongoDB funcionar perfeitamente até hoje nos projetos que passei. O principal problema foi causado por aquilo que mais temo: inércia mental.

Há aqueles momentos em que as pessoas estão tão habituadas com o modelo relacional que simplesmente não conseguem aceitar alguns fatos fundamentais sobre o MongoDB:

  • Ele não foi feito para lidar com relacionamentos entre diferentes documentos. Documentos embarcados funcionam bem, mas quando você vai lidar com documentos em outras coleções, ou mesmo na mesma, o máximo que você tem é um quebra galho.
  • MongoDB não foi feito para ter integridade referencial.
  • Se os atributos da sua estrutura de dados são fixos e previsíveis, o registro é a melhor opção, não o documento.
  • MongoDB não é uma base de dados relacional
  • Não há uma implementação nativa de transações ACID entre documentos e nem era objetivo dos projetistas deste SGBD fazer isto.

Se seu sistema exige relacionamentos e integridade referencial  por que não usar uma base relacional? Quer fazer bonito pra algum idiota? Use persistência poliglota! MongoDB e seu SGBD relacional favorito, cada um em seu galho. Por que não tirar o melhor dos dois mundos?

(implementar integridade referencial manualmente é muito triste)

Dicas

A seguir estão algumas dicas que ajudam bastante na adoção do MongoDB. Claro que há inúmeras outras, mas estas são as que considero mais importantes.

Use alguma biblioteca/framework de mapeamento

Uma boa opção é o Spring Data para MongoDB. O modo como lida com o mapeamento de relacionamento entre documentos é muito simples e próximo daquele que estamos acostumados a trabalhar com JPA.

(reparem na frase: “que estamos acostumados a trabalhar com JPA”. É a tentativa inconsciente de aproximar o MongoDB do modelo relacional! (ainda escrevo mais sobre isto no futuro))

Mas já lhe digo que o Spring Data para MongoDB não é perfeito: longe disto. Há bugs e limitações, mas o lado positivo é que se você abrir uma issue para a equipe de desenvolvimento do projeto e esta  for bem descrita (dica: envie código reproduzindo o problema), eles resolverão rapidamente o problema. Quase todas as issues que abri foram atendidas em no máximo duas semanas, algumas na mesma semana de abertura.

Há outras alternativas também, como o Morphia, que funcionam muito bem, mas como nosso projeto era baseado em Spring, era mais interessante usar algo pertencente ao mesmo stack.

(ao que tudo indica o desenvolvimento do Spring Data está bem mais ativo também)

Conheça BEM o driver Java (ou da sua linguagem) do MongoDB

Estes frameworks de mapeamento quebram um bom galho mas há um preço: muitas vezes são lentos. Em aplicações que precisem de alto desempenho você irá observar que seu gargalo não estará no MongoDB, mas sim no código Java presente nestas bibliotecas.

Sendo assim, conhecendo bem o driver Java do MongoDB irá lhe ajudar horrores na hora em que precisar lidar com estes gargalos. Se seu sistema for basicamente CRUD, aí sim você pode ficar apenas com as bibliotecas.

Outro ponto fundamental é que pelo driver Java você consegue fazer praticamente qualquer coisa no MongoDB. Muitas vezes há um ou outro recurso que não está presente ainda na sua API de mapeamento favorita.

Precisa de transacionalidade entre documentos com MongoDB?

Se respondeu a sim esta pergunta e não quer usar uma base relacional, sua vida acaba de ficar  difícil, mas não impossível. MongoDB oferece atomicidade em operações sobre um único documento, mas não entre documentos. Sempre tenha isto em mente.

Você pode implementar manualmente transacionalidade entre documentos, mas esta será bem limitada. No site do MongoDB há um tutorial que você pode consultar. O problema é que isto dá muito trabalho.

Vou falar sobre uma solução melhor para este problema mais a frente.

Não pensou no espaço que estes bancos de dados ocupam?

Yeap, eu já havia falado sobre isto antes. As bases de dados do MongoDB podem crescer bastante se você não ficar atento. Leve isto em consideração se não quiser levar um susto com o custo do seu storage. É sempre bom fazer algumas simulações do ambiente de produção antes de adotar o MongoDB: irá lhe poupar muito tempo, dinheiro e saúde.

Lembra aquela solução que havia prometido? Ei-la!

Considere seriamente a adoção do TokuMX ao invés do MongoDB

tokutek

Sabia que o MongoDB tem um irmão gêmeo bem mais charmoso? Trata-se de uma distribuição alternativa chamada TokuMX: também é open source e é desenvolvido por uma empresa chamada TokuTek.

Bom: o que ele tem de bom?

  • Resolve seu problema de espaço de armazenamento: uma de nossas bases no MongoDB ocupa 400Mb. No TokuMX? 15Mb.
  • TokuMX implementa transação ACID entre documentos. Sim, você leu certo, e ela funciona MUITO bem.
  • Apresenta desempenho bastante superior

E o melhor: 100% compatível. Se você trocar sua instalação MongoDB pelo TokuMX sua aplicação não notará diferença alguma além da melhoria de desempenho. Até este momento só vi dois poréns com o TokuMX:

  • Ainda não há uma distribuição para Windows.
  • Infelizmente as bibliotecas atuais não oferecem suporte nativo à implementação ACID do MongoDB: você terá de usar o driver nativo para obter este resultado. Existe uma issue no projeto Spring Data pedindo este suporte, mas não é prioritária ainda (mesmo eu pedindo :) ).

Treine BEM a sua equipe

Este é um ponto fundamental: você precisa expor para os membros do seu time o modo como devemos pensar a persistência fora do modelo relacional. É a única cura que conheço para o problema da inércia mental.

Conclusões

Estas foram minhas experiências com o MongoDB. Quanto mais cedo você detectar estas dificuldades que mencionei, melhor. Espero com este post ter dado minha contribuição. Devo confessar que até hoje a maior parte das reclamações que vejo sobre o MongoDB não são culpas da ferramenta, mas sim do seu mal uso.

E, pra finalizar MESMO: experimentem o TokuMX, é um produto muito superior e vai te poupar muito tempo. :)

11 comentários em “Minha experiência com MongoDB: erros, acertos e dicas”

  1. Henrique, muito bom o post, vejo situação semelhante com ElasticSearch, algumas pessoas insistem em utilizá-lo como banco de dados e querendo normalizar os dados o tempo todo. Não conhecia o TokuMX, excelente dica.

    []’s

    1. Kico (Henrique Lobo Weissmann)

      Oi Isaias, valeu!
      TokuMX é como o MongoDB devia ter sido desde o primeiro dia.

      Os nomes é que são péssimos né? :D

  2. Muito bom, Kiko!

    Nunca trabalhei com o MongoDB, mas sempre tento acompanhar na medida do possível. Também não conhecia o TokuMX, bem interessante!

    Acredito que seja comum os desenvolvedores levarem sua base de conhecimento relacional para um MongoDB ou outro NoSQL, assim como levam o conhecimento procedural p/ o mundo OO. No mais, um amigo costuma dizer que relacionamentos no MongoDB devem ser pensados como “Xerox grampeadas” :-)

    Você disse que não tem uma distribuição para Windows, então estão usando Vagrant nos ambientes de desenvolvimento? Acho que seria uma solução para os desenvolvedores que insistem ou não podem sair do ambiente Windows!

    Um abraço e parabéns pelo post!

    1. Kico (Henrique Lobo Weissmann)

      Oi Rafael, valeu!

      a solução para o ambiente de desenvolvimento é simplesmente ter mais de uma instância executando em uma máquina Linux com portas diferentes. Só conheço o Vagrant de nome.

  3. Oi Kiko,

    Pois é, aconselho o uso do Vagrant. Hoje em dia eu levanto todos os meus bancos de dados e ambientes malucos usando Vagrant (MySQL, Postgres, Oracle, Firebird etc). Seria bem simples levantar uma VM Ubuntu já com o TokuMX ou MongoDB instalado e rodando – se brincar já deve ter vários repositórios prontos no Github!

    Vale a pena você pesquisar sobre Vagrant, bem útil e automatiza muito o desenvolvimento.

  4. Muito bom o seu post.

    No post vc aconselha utilizar o NoSql para complementar sua aplicação Relacional.

    Minha duvida é em um projeto que utilizo banco de dados relacional e alguma funcionalidade utilizarei o MongoDB, as informações referente a essa funcionalidade que hoje estão no meu relacional serão duplicadas? Ou seja, eu replicarei para o MongoDB para que seja possível fazer minhas consultas?

    Um cadastro de pedidos e produtos eu teria minhas tabelas Pedidos ->——Produtos no banco de dados relacional e no Mongodb eu teria meu documento Peidido com a coleção de produtos?

    Seria essa a ideia? Trabalhar com a mesma informação nos dois bancos?

    1. Kico (Henrique Lobo Weissmann)

      Oi Alexandre, obrigado!

      O ideal é você incluir no MongoDB apenas informações complementares. Não precisa duplicar dados por lá.

      Imagine um cadastro que possua uma parte cujos atributos são dinâmicos. Você armazenaria no MongoDB apenas estes atributos em um documento que possuísse uma chave que apontasse para o registro relacionado no seu SGBD relacional.

  5. Se eu tiver de usar um driver nativo para utilizar o TokuMX com certeza sempre terei um desempenho superior, ainda que a comparação não fosse exagerada.
    A razão é bem simples: experimente querys no MongoDb com e sem driver nativo. ORMs como o Mongoose são até 10 vezes mais lentos que um drive nativo consumindo os dados.

Deixe uma resposta

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

Rolar para cima