David Hows Peter Membrey Eelco Plugge
Novatec
Original English language edition published by Apress, Copyright © 2014 by Apress, Inc.. Portugueselanguage edition for Brazil copyright © 2015 by Novatec Editora. All rights reserved. Edição original em Inglês publicada pela Apress, Copyright © 2014 by Apress, Inc. Edição em Português para o Brasil copyright © 2015 pela Novatec Editora. Todos os direitos reservados. © Novatec Editora Ltda. [2015]. Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a reprodução desta obra, mesmo parcial, por qualquer processo, sem prévia autorização, por escrito, do autor e da Editora. Editor: Rubens Prates Tradução: Lúcia A. Kinoshita Revisão gramatical: Patrizia Zagni Editoração eletrônica: Carolina Kuwabata Assistente editorial: Priscila A. Yoshimatsu ISBN: 978-85-7522-422-9 OG20150305 Histórico de impressões: Março/2015
Primeira edição
Novatec Editora Ltda. Rua Luís Antônio dos Santos 110 02460-000 – São Paulo, SP – Brasil Tel.: +55 11 2959-6529 Email: novatec@novatec.com.br Site: www.novatec.com.br Twitter: twitter.com/novateceditora Facebook: facebook.com/novatec LinkedIn: linkedin.com/in/novatec
capítulo 1
Introdução ao MongoDB
Pense em um mundo em que utilizar um banco de dados seja tão simples que você logo se esqueça de que está usando um. Pense em um mundo em que velocidade e escalabilidade simplesmente funcionam, e em que não haja necessidade de ter configurações complicadas ou fazer instalações complexas. Imagine poder focar somente na tarefa que estiver à mão, fazer o que deve ser feito e então – somente para variar – sair do trabalho no horário. Isso pode soar um pouco fantasioso, mas o MongoDB promete ajudar a fazer tudo isso (e muito mais). O MongoDB (derivado da palavra humongous em inglês, que quer dizer gigantesco) é um tipo relativamente novo de banco de dados que não tem conceitos de tabelas, esquemas, SQL ou linhas. Não há transações, conformidade com ACID1, joins (junções), chaves estrangeiras nem vários outros recursos que tendem a causar dores de cabeça nas primeiras horas da manhã. Em suma, o MongoDB é um banco de dados bem diferente daqueles com que você provavelmente está acostumado a trabalhar, em especial, se você já usou um RDBMS (Relational Database Management System, ou Sistema de gerenciamento de banco de dados relacional) anteriormente. De fato, você pode até estar balançando a cabeça, surpreso com a falta dos recursos chamados “padrão”. Não tenha medo! Nas próximas páginas, você conhecerá a história do MongoDB e seus princípios orientadores, além dos motivos pelos quais a equipe do MongoDB optou por este design. Também faremos um tour guiado pela lista de recursos do MongoDB, oferecendo detalhes somente 1 N.T.: Atomicity, Consistency, Isolation and Durability, ou Atomicidade, Consistência, Isolamento e Durabilidade.
16
Capítulo 1 ■ Introdução ao MongoDB
17
o suficiente para garantir que você seja totalmente conquistado por este assunto pelo restante do livro. Começaremos dando uma olhada na filosofia e nas ideias por trás da criação do MongoDB bem como em algumas das decisões de design interessantes e, de certo modo, controversas. Exploraremos o conceito de banco de dados orientado a documentos, de que forma esses bancos de dados trabalham em conjunto e quais são seus pontos fortes e seus pontos fracos. Também exploraremos o JSON e analisaremos de que modo ele se aplica ao MongoDB. Para concluir, daremos uma olhada em alguns dos recursos dignos de nota do MongoDB.
Examinando a filosofia do MongoDB Assim como todos os projetos, o MongoDB tem um conjunto de princípios filosóficos de design que ajuda a orientar o seu desenvolvimento. Nesta seção, examinaremos alguns dos princípios fundamentais do banco de dados.
Utilizando a ferramenta correta para o trabalho correto O princípio filosófico mais importante na base do MongoDB é a noção de que um só tamanho não é ideal para todos. Durante vários anos, os bancos de dados relacionais (SQL) tradicionais (o MongoDB é um banco de dados orientado a documentos) foram usados para armazenar conteúdos de todos os tipos. Não importava se os dados fossem ou não adequados ao modelo relacional (usado em todos os bancos de dados RDBMS, por exemplo, MySQL, PostgresSQL, SQLite, Oracle, MS SQL Server e assim por diante); os dados eram colocados ali, de qualquer maneira. Parte do motivo para isso está no fato de que, falando de modo geral, é muito mais fácil (e mais seguro) ler e escrever em um banco de dados do que escrever em um sistema de arquivos. Se você ler qualquer livro que ensine PHP – por exemplo, o livro PHP for Absolute Beginners, de Jason Lengstorf (Apress, 2009) –, provavelmente descobrirá, quase de imediato, que o banco de dados é usado para armazenar informações, e não o sistema de arquivos. É muito mais fácil fazer o trabalho dessa maneira. E embora usar um banco de dados como uma área de armazenamento funcione, os
18
Introdução ao MongoDB
desenvolvedores sempre tiveram de trabalhar contra o fluxo. Normalmente, se não estivermos usando o banco de dados da maneira para a qual ele foi projetado para ser utilizado, esse fato será óbvio; qualquer pessoa que já tenha tentado armazenar informações com dados um pouco mais complexos, tenha precisado criar cinco tabelas e tentado reunir tudo isso sabe do que estamos falando! A equipe do MongoDB decidiu que não iria criar outro banco de dados que tentasse fazer tudo para todos. Em vez disso, ela quis criar um banco de dados que trabalhasse com documentos em vez de linhas, que fosse extremamente rápido, amplamente escalável e fácil de usar. Para isso, a equipe precisou deixar algumas funcionalidades de lado, o que significa que ele não é um candidato ideal para determinadas situações. Por exemplo, a ausência de suporte a transações implica que ele não deve ser usado para criar uma aplicação de contabilidade. Apesar do que foi dito, o MongoDB pode ser perfeito para ser usado em parte da aplicação mencionada anteriormente (por exemplo, para armazenar dados complexos). Contudo isso não é um problema, pois não há motivos para não usarmos um RDBMS tradicional para os componentes relativos à contabilidade e o MongoDB para o armazenamento de documentos. Soluções híbridas como esta são bastante comuns e você pode vê-las em aplicações sendo executadas em ambientes de produção, por exemplo, no site do New York Times. Depois que se sentir à vontade com a ideia de que o MongoDB pode não resolver todos os seus problemas, você descobrirá que para alguns deles o MongoDB é perfeito, como aqueles relacionados a web analytics (pense em um Google Analytics em tempo real para o seu site) e ao uso de estruturas complexas de dados (por exemplo, postagens de blog e comentários). Se você ainda não estiver convencido de que o MongoDB é uma ferramenta séria de banco de dados, sinta-se à vontade para pular para a seção “Examinando a lista de recursos”, em que você encontrará uma lista impressionante de recursos do MongoDB. Nota: a falta de transações e de outros recursos tradicionais de banco de dados não quer dizer que o MongoDB seja instável ou que não possa ser usado para administrar dados importantes.
Capítulo 1 ■ Introdução ao MongoDB
19
Outro conceito fundamental por trás do design do MongoDB está no fato de que sempre deve haver mais de uma cópia do banco de dados. Se um único banco de dados falhar, ele simplesmente poderá ser restaurado a partir de outros servidores. Como o objetivo do MongoDB é ser o mais rápido possível, ele utiliza alguns atalhos que dificultam a recuperação quando houver uma falha. Os desenvolvedores acreditam que as falhas mais graves provavelmente farão um computador deixar de funcionar, de qualquer modo; isso significa que mesmo que o banco de dados fosse perfeitamente restaurado, ele não poderia ser utilizado. Lembre-se de que o MongoDB não tenta ser ideal em tudo para todas as pessoas. Porém, para atender a diversos propósitos (como desenvolver uma aplicação web), ele pode ser uma ferramenta incrível na implementação de sua solução. Agora você já conhece a origem do MongoDB. Ele não tenta ser o melhor em tudo e admite prontamente que não é ideal para todos. Entretanto, para aqueles que optarem por usá-lo, ele oferece um banco de dados cheio de recursos, orientado a documentos e otimizado quanto à velocidade e à escalabilidade. Ele também pode ser executado praticamente em qualquer ambiente que você queira que ele execute. O site do MongoDB inclui downloads para Linux, Mac OS, Windows e Solaris. O MongoDB é bem-sucedido em relação a todos esses objetivos, e é por isso que usá-lo (pelo menos para nós) é como se fosse um sonho. Não é preciso se preocupar em espremer seus dados para inseri-los em uma tabela – basta reuni-los e passá-los ao MongoDB para que sejam manipulados. Considere o exemplo a seguir do mundo real. Uma aplicação recente em que o coautor Peter Membrey trabalhou, precisava armazenar um conjunto de resultados de pesquisa do eBay. Poderia haver qualquer quantidade de resultados (até cem) e era preciso ter uma maneira simples de associar esses resultados aos usuários de seu banco de dados. Se Peter estivesse usando MySQL, ele deveria criar uma tabela para armazenar os dados, implementar o código para armazenar seus resultados e, em seguida, implementar mais código para reunir tudo novamente. Este é um cenário razoavelmente comum e com o qual a maioria dos desenvolvedores se depara normalmente. Em geral, simplesmente seguimos em frente para resolver o problema; entretanto, nesse projeto, ele estava usando o MongoDB de modo que a situação transcorreu de forma um pouco diferente.
20
Introdução ao MongoDB
Especificamente, ele adicionou a linha de código a seguir: request['ebay_results'] = ebay_results_array collection.save(request)
Nesse exemplo, request é o documento de Peter, ebay_results é a chave e ebay_result_array contém os resultados do eBay. A segunda linha salva as alterações. Quando esse documento for acessado no futuro, ele terá os resultados do eBay exatamente no mesmo formato anterior. Não foi necessário usar nenhum SQL; ele não precisou realizar nenhuma conversão nem criar nenhuma tabela nova ou implementar qualquer código especial – o MongoDB simplesmente funcionou. O problema foi resolvido, Peter terminou seu trabalho mais cedo e foi para casa no horário.
Ausência de suporte inato a transações A seguir, apresentaremos outra decisão importante de design feita pelos desenvolvedores do MongoDB: o banco de dados não inclui semântica para transações (o elemento que oferece garantias sobre a consistência e o armazenamento de dados). Essa é uma contrapartida sólida, baseada no objetivo do MongoDB de ser simples, rápido e escalável. Depois que esses recursos pesados são deixados de lado, torna-se muito mais fácil escalar horizontalmente. Em geral, com um RDBMS tradicional, o desempenho é melhorado por meio da compra de um computador maior e mais potente. Essa operação consiste em escalar verticalmente, mas pode levar você somente até certo ponto. Com a escalação horizontal, em vez de ter um computador enorme, você terá vários computadores menores e menos potentes. Historicamente, clusters de servidores como esse eram excelentes para efetuar balanceamento de carga em sites, porém os bancos de dados sempre foram um problema por causa das limitações de seus designs internos. Você pode achar que a ausência desse suporte constitui uma falta de comprometimento do banco de dados; entretanto muitas pessoas se esquecem de que um dos tipos mais populares de tabela no MySQL (MYISAM – que, por acaso, também é o default) também não suporta transações. Esse fato não impediu que o MySQL se tornasse e continuasse a ser o
Capítulo 1 ■ Introdução ao MongoDB
21
banco de dados de código aberto dominante por muito mais de uma década. Como ocorre com a maioria das escolhas quando desenvolvemos soluções, usar o MongoDB será uma questão de preferência pessoal e de avaliar se a relação de custo-benefício será adequada ao seu projeto. Nota: o MongoDB oferece durabilidade quando usado em conjunto com pelo menos três servidores, que é o mínimo recomendado para instalações em ambiente de produção. É possível fazer o membro principal da réplica esperar que um ou mais membros secundários confirmem a recepção dos dados antes que o membro principal confirme que esses dados foram aceitos.
JSON e MongoDB O JSON (Java Script Object Notation) é mais que uma excelente maneira de trocar dados; é também uma ótima maneira de armazená-los. Um RDBMS é altamente estruturado, com vários arquivos (tabelas) que armazenam partes individuais. O MongoDB, por outro lado, armazena tudo em um único documento. Ele é como o JSON nesse aspecto, e esse modelo oferece um modo sofisticado e expressivo de armazenar dados. Além do mais, o JSON descreve eficientemente todo o conteúdo de um dado documento, de modo que não há necessidade de especificar a estrutura do documento de antemão. O JSON é desprovido de esquemas (schemaless, ou seja, não exige um esquema), pois os documentos podem ser atualizados individualmente ou alterados de modo independente de qualquer outro documento. Como bônus, o JSON também proporciona um desempenho excelente ao manter todos os dados relacionados em um só local. O MongoDB, na verdade, não usa JSON para armazenar dados; em vez disso, ele usa um formato aberto de dados chamado BSON – que é a abreviatura de binary JSON (JSON binário) – desenvolvido pela equipe do MongoDB. Na maior parte das vezes, usar BSON no lugar de JSON não mudará o modo como você trabalhará com os seus dados. O BSON torna o MongoDB mais rápido ainda ao fazer com que seja muito mais fácil para um computador processar e efetuar pesquisas nos documentos.
22
Introdução ao MongoDB
O BSON também acrescenta alguns recursos que não estão disponíveis no JSON padrão, incluindo a capacidade de adicionar tipos para tratamento de dados binários. Veremos o BSON com mais detalhes na seção “Usando armazenamento orientado a documentos (BSON)”, mais adiante neste capítulo. A especificação original do JSON pode ser encontrada na RFC 4627 e foi escrita por Douglas Crockford. O JSON permite que estruturas complexas de dados sejam representadas em um formato-texto simples, legível aos seres humanos, que, em geral, é considerado muito mais fácil de ler e de entender que o XML. Assim como o XML, o JSON foi concebido como uma maneira de trocar dados entre um cliente web (por exemplo, um navegador) e as aplicações web. Quando combinado com a maneira sofisticada pela qual o JSON pode descrever objetos, sua simplicidade fez com que ele se tornasse a opção preferida de formato para troca de dados para a maioria dos desenvolvedores. Você pode estar se perguntando o que queremos dizer aqui com estruturas complexas de dados. Historicamente, os dados eram trocados por meio do formato CVS (Comma-Separated Values, ou Valores separados por vírgula); na realidade, essa abordagem ainda é bastante comum hoje em dia. O CSV é um formato-texto simples, em que as linhas são separadas por um caractere de quebra de linha e os campos, com uma vírgula. Por exemplo, um arquivo CSV pode ter um aspecto semelhante a: Membrey, Peter, +852 1234 5678 Thielen, Wouter, +81 1234 5678
Uma pessoa pode observar esses dados e perceber rapidamente quais informações estão sendo comunicadas. Ou talvez não – o número na terceira coluna é um número de telefone ou de fax? Pode até mesmo ser o número de um pager. Para evitar essa ambiguidade, os arquivos CSV geralmente têm um campo de cabeçalho, em que a primeira linha define o que o arquivo contém. O trecho a seguir expande um pouco o exemplo anterior: Lastname, Firstname, Phone Number Membrey, Peter, +852 1234 5678 Thielen, Wouter, +81 1234 5678
Capítulo 1 ■ Introdução ao MongoDB
23
Muito bem, assim está um pouco melhor. Mas vamos supor agora que algumas pessoas do arquivo CSV tenham mais de um número de telefone. Você poderia acrescentar outro campo para um número de telefone comercial, porém irá se deparar com um novo conjunto de problemas se quiser ter vários números de telefone comerciais. E terá ainda outro conjunto de problemas se quiser também incorporar vários endereços de email. A maioria das pessoas tem mais de um, e esses endereços geralmente não podem ser claramente definidos como de uso particular ou profissional. Repentinamente, o CSV começa a mostrar suas limitações. Os arquivos CSV são adequados somente para armazenar dados que sejam simples e que não tenham valores repetidos. De modo semelhante, não é incomum que vários arquivos CSV sejam disponibilizados, cada um com partes separadas de informações. Esses arquivos são então combinados (geralmente em um RDBMS) para criar o quadro geral. Como exemplo, uma grande empresa de vendas a varejo pode receber dados de vendas na forma de arquivos CSV de cada uma de suas lojas no final de cada dia. Esses arquivos devem ser combinados antes de a empresa poder ver o seu desempenho em um dado dia. Esse processo não é exatamente simples e, certamente, as chances de um erro ser cometido aumentarão à medida que a quantidade de arquivos necessários aumentar. O XML, de modo geral, soluciona esse problema, porém utilizar XML, na maioria das situações, é um pouco parecido com usar uma marreta para quebrar uma noz: funciona, mas parece ser um exagero. O motivo para isso é que o XML é altamente extensível. Em vez de definir um formato de dados particular, o XML define a maneira de especificar um formato de dados. Isso pode ser útil quando houver necessidade de trocar dados complexos e altamente estruturados; no entanto, para uma troca simples de dados, com frequência, isso resultará em muito trabalho. Com efeito, esse cenário deu origem à expressão “XML hell” (inferno do XML). O JSON oferece um meio de troca de dados satisfatório. De modo diferente do CVS, ele pode armazenar conteúdo estruturado, porém, diferentemente do XML, o JSON faz o conteúdo ser fácil de entender e simples de usar. Vamos retornar ao exemplo anterior, mas desta vez, usaremos JSON no lugar de CSV:
24
Introdução ao MongoDB { "firstname": "Peter", "lastname": "Membrey", "phone_numbers": [ "+852 1234 5678", "+44 1234 565 555" ] }
Nessa versão do exemplo, cada objeto JSON (ou documento) contém todas as informações necessárias para que ele possa ser compreendido. Se você observar phone_numbers, verá que ele contém uma lista de números diferentes. Essa lista pode ser tão longa quanto se queira. Além disso, poderíamos ser mais específicos quanto ao tipo de número registrado, como no exemplo a seguir: { "firstname": "Peter", "lastname": "Membrey", "numbers": [ { "phone": "+852 1234 5678" }, { "fax": "+44 1234 565 555" } ] }
Essa versão do exemplo apresenta melhorias quanto a alguns aspectos. Agora podemos ver claramente o que cada número representa. O JSON é extremamente expressivo e, embora seja bem fácil codificá-lo manualmente, em geral, o JSON é gerado automaticamente, por meio de software. Por exemplo, o Python inclui um módulo cujo nome (de certo modo, previsível) é json, que converte objetos Python automaticamente para JSON. Como é suportado e utilizado em várias plataformas, o JSON é uma escolha ideal para efetuar troca de dados.
Capítulo 1 ■ Introdução ao MongoDB
25
Ao adicionar itens como a lista de números de telefone, na realidade, você estará criando o que é conhecido como um documento embutido (embedded document). Isso acontece sempre que um conteúdo complexo for adicionado, por exemplo, uma lista (ou um array, para usar o termo favorecido pelo JSON). Falando de modo geral, também há uma distinção lógica. Por exemplo, um documento Person pode ter vários documentos Address embutidos. De modo semelhante, um documento Invoice pode ter vários documentos LineItem embutidos. É claro que o documento embutido Address também pode ter seu próprio documento embutido que contenha números de telefone, por exemplo. A opção de incluir ou não um documento em particular é determinada quando você decidir de que modo suas informações serão armazenadas. Normalmente, isso é chamado de design de esquema (schema design). Pode parecer estanho referir-se a design de esquema quando o MongoDB é considerado um banco de dados sem esquemas. Entretanto, embora ele não o force a criar um esquema nem garanta que aplicará um que você tenha criado, continua sendo necessário pensar na forma de organização de seus dados. Daremos uma olhada nisso com mais detalhes no capítulo 3.
Adotando uma abordagem não relacional Melhorar o desempenho com um banco de dados relacional normalmente é uma tarefa simples: você compra um servidor maior e mais rápido. E isso funciona muito bem até o ponto em que não haverá um servidor maior disponível para comprar. Nesse momento, a única opção será dividir o sistema em dois servidores. Isso pode parecer fácil, porém é um problema para a maioria dos bancos de dados. Por exemplo, nem o MySQL nem o PostgresSQL podem executar um único banco de dados em dois servidores, em que ambos possam ler e gravar dados (com frequência, isso é chamado de cluster ativo/ativo). E embora o Oracle possa fazer isso com sua arquitetura RAC (Real Application Clusters) impressionante, você pode esperar contrair uma dívida caso queira usar essa solução – implementar uma solução baseada em RAC exige vários servidores, armazenamento compartilhado e várias licenças de software.
26
Introdução ao MongoDB
Você pode estar se perguntando por que ter um cluster ativo/ativo em dois bancos de dados é tão difícil. Quando você fizer queries em seu banco de dados, ele deverá encontrar todos os dados relevantes e associá-los. As soluções RDBMS têm diversas maneiras engenhosas de melhorar o desempenho, porém todas elas dependem de ter uma imagem completa dos dados disponíveis. E é nesse ponto que você atinge uma parede: essa abordagem simplesmente não funciona quando metade dos dados estiver em outro servidor. É claro que podemos ter um banco de dados pequeno que simplesmente receba várias solicitações de modo que será preciso apenas dividir a carga de trabalho. Infelizmente, nesse caso, você atingirá outra parede. É preciso garantir que os dados gravados no primeiro servidor estejam disponíveis no segundo. E você irá se deparar com problemas adicionais se forem feitas atualizações em dois masters (mestres) diferentes simultaneamente. Por exemplo, você deve determinar qual atualização é a correta. Outro problema com que você pode se deparar é o seguinte: uma pessoa pode fazer uma consulta no segundo servidor em busca de informações que acabaram de ser gravadas no primeiro, porém essas informações ainda não foram atualizadas no segundo servidor. Ao considerar todos esses problemas, fica fácil ver por que a solução da Oracle é tão cara – essas questões são extremamente difíceis de resolver. O MongoDB soluciona os problemas de clusters ativo/ativo de uma maneira bastante inteligente: ele os evita totalmente. Lembre-se de que o MongoDB armazena dados em documentos BSON, portanto os dados são autocontidos. Ou seja, embora documentos semelhantes sejam armazenados juntos, os documentos individuais não são constituídos de relacionamentos. Isso significa que tudo que você precisar estará em um só local. Como as queries no MongoDB procuram chaves e valores específicos em um documento, essas informações podem estar facilmente espalhadas em tantos servidores quanto estiverem disponíveis. Cada servidor verificará o conteúdo que tiver e retornará o resultado. Isso efetivamente permite uma escalabilidade e um desempenho quase lineares. Como bônus, essa solução nem mesmo exige que você assuma uma nova dívida para pagar por essa funcionalidade.
Capítulo 1 ■ Introdução ao MongoDB
27
É preciso admitir que o MongoDB não oferece uma replicação master/master (master/master replication), em que dois servidores diferentes possam aceitar solicitações de escrita. Entretanto, ele oferece o recurso de sharding, que permite que os dados sejam separados em vários computadores, cada qual responsável por atualizar partes diferentes do conjunto de dados. A vantagem desse design está no fato de que, enquanto algumas soluções permitem ter dois bancos de dados master, o MongoDB pode potencialmente escalar para centenas de computadores tão facilmente quanto pode executar em dois.
Escolhendo entre desempenho versus recursos O desempenho é importante, porém o MongoDB também oferece um amplo conjunto de recursos. Já discutimos alguns dos recursos que não estão implementados, e você pode estar um pouco cético a respeito da argumentação de que o MongoDB atinge seu impressionante desempenho parcialmente pela exclusão criteriosa de determinadas funcionalidades comuns a outros bancos de dados. No entanto, há sistemas análogos de bancos de dados disponíveis que são extremamente rápidos, mas que também são extremamente limitados, por exemplo, aqueles que implementam um armazenamento do tipo chave/valor. Um exemplo perfeito é o memcached. Essa aplicação foi criada para proporcionar caching de dados de alta velocidade e é extremamente rápida. Quando usada para fazer cache de conteúdo de sites, ela pode agilizar uma aplicação e deixá-la várias vezes mais rápida. Essa aplicação é usada por sites extremamente grandes como o Facebook e o LiveJournal. O truque está no fato de essa aplicação ter duas deficiências significativas; em primeiro lugar, é um banco de dados somente em memória. Se houver queda de energia, todos os dados serão perdidos. Em segundo, você não pode realmente pesquisar dados usando o memcached; você pode somente solicitar chaves específicas. Isso pode soar como limitações sérias, mas é preciso lembrar dos problemas para os quais o memcached foi criado para resolver. Antes de tudo, ele é uma cache de dados. Isso quer dizer que não foi projetado para armazenar dados permanentemente, mas somente para prover uma
28
Introdução ao MongoDB
camada de caching para o seu banco de dados existente. Ao criar uma página web dinâmica, em geral, você solicitará dados bem específicos (por exemplo, o conteúdo dos dez artigos mais acessados no momento). Isso significa que você pode pedir esses dados especificamente ao memcached – não há necessidade de realizar uma pesquisa. Se a cache estiver desatualizada ou vazia, você fará uma query em seu banco de dados como faria normalmente, comporá os dados e, em seguida, irá armazená-los no memcached para serem usados futuramente. Depois que tiver aceitado essas limitações, você verá como o memcached oferece um desempenho excelente ao implementar um conjunto bem limitado de funcionalidades. Esse desempenho, a propósito, não tem correspondente em um banco de dados tradicional. Apesar do que foi dito, o memcached certamente não pode substituir um RDBMS. O aspecto importante a se ter em mente é que ele não foi criado para isso. Ao ser comparado com o memcached, o MongoDB é bem rico em recursos. Para ser útil, o MongoDB deve oferecer um conjunto sólido de funcionalidades, por exemplo, a capacidade de procurar documentos específicos. Ele também deve ser capaz de armazenar esses documentos em disco para que eles possam sobreviver a uma reinicialização. Felizmente, o MongoDB disponibiliza recursos suficientes para ser um forte concorrente a ser usado na maioria das aplicações web e também em vários outros tipos de aplicação. Assim como o memcached, o MongoDB não é um banco de dados de “tamanho único”, que sirva para todos. Como normalmente é o caso em computação, deve haver um compromisso no que diz respeito ao custo-benefício para que os objetivos pretendidos para a aplicação sejam atingidos.
Executando o banco de dados em qualquer lugar O MongoDB está implementado em C++, o que faz com que seja relativamente fácil portar e/ou executar a aplicação praticamente em qualquer lugar. Atualmente, os binários podem ser baixados do site do MongoDB e estão disponíveis para Linux, Mac OS, Windows e Solaris. Há também diversas versões oficiais disponíveis para Fedora e CentOS, entre outras plataformas. Você pode até mesmo fazer o download do código-fonte
Capítulo 1 ■ Introdução ao MongoDB
29
e gerar o seu próprio MongoDB, embora seja recomendável utilizar os binários disponibilizados sempre que for possível. Todos os binários estão disponíveis tanto para versões 32 bits quanto para 64 bits. Cuidado: a versão para 32 bits do MongoDB está limitada a bancos de dados de 2 GB ou menos. Isso se deve ao fato de o MongoDB utilizar arquivos mapeados em memória internamente para conseguir um bom desempenho. Tudo o que tiver mais de 2 GB em um sistema de 32 bits exigiria estratégias sofisticadas que não seriam rápidas, além de complicarem o código da aplicação. A posição oficial em relação a essa limitação é que os ambientes de 64 bits estão facilmente disponíveis e, sendo assim, aumentar a complexidade do código não constitui uma boa contrapartida. A versão para 64 bits, em todo caso, não tem essa restrição.
Os requisitos modestos do MongoDB permitem que ele seja executado em servidores altamente capacitados ou em máquinas virtuais, e até mesmo para aplicações baseadas na nuvem. Ao manter a simplicidade e focar na velocidade e na eficiência, o MongoDB proporciona um desempenho sólido, independentemente do local em que você optar por implantá-lo.
Encaixando todas as partes Antes de darmos uma olhada na lista de recursos do MongoDB, devemos analisar alguns termos básicos. O MongoDB não exige muito no que diz respeito a conhecimentos especializados para começarmos a trabalhar com ele, e vários dos termos específicos podem ser, de modo geral, traduzidos para equivalentes em RDBMS, com os quais você provavelmente já está familiarizado. Mas não se preocupe; explicaremos cada termo de forma completa. Mesmo que você não esteja familiarizado com a terminologia-padrão dos bancos de dados, você conseguirá acompanhar facilmente as explicações.
Gerando ou criando uma chave Um documento representa a unidade de armazenamento do MongoDB. Em um RDBMS, essa unidade é chamada de linha. Entretanto, os
30
Introdução ao MongoDB
documentos são muito mais do que linhas, pois podem armazenar informações complexas como listas, dicionários e até mesmo listas de dicionários. Em oposição a um banco de dados tradicional, em que uma linha é fixa, um documento no MongoDB pode ser composto por qualquer quantidade de chaves e valores (você aprenderá mais sobre isso na próxima seção). Em última instância, uma chave nada mais é do que um rótulo; de modo geral, é equivalente ao nome que você daria a uma coluna em um RDBMS. Uma chave é usada para referenciar partes dos dados em seu documento. Em um banco de dados relacional, sempre deve haver uma maneira de identificar unicamente um dado registro; caso contrário, será impossível referenciar uma linha específica. Para isso, você deve incluir um campo que armazene um valor único (chamado de chave primária) ou um conjunto de campos que possa identificar unicamente a linha especificada (chamada de chave primária composta). O MongoDB exige que cada documento tenha um identificador único, basicamente pelo mesmo motivo; no MongoDB, esse identificador se chama _id. A menos que você especifique um valor para esse campo, ele gerará um valor único para você. Mesmo no mundo bem consolidado dos bancos de dados RDBMS, não há consenso em relação a usar uma chave única fornecida pelo banco de dados ou gerá-la por conta própria. Recentemente, tem se tornado mais popular permitir que o banco de dados crie a chave para você. O motivo para isso é que as pessoas têm o péssimo hábito de mudar números únicos criados por elas, por exemplo, os números de placa de veículos. Por exemplo, em 2001, o Reino Unido implementou um novo esquema para número de placas que era totalmente diferente do sistema anterior. O fato é que o MongoDB pode lidar perfeitamente com esse tipo de alteração; no entanto, é provável que você deverá pensar muito bem caso tenha usado a placa de registro do veículo como sua chave primária. Um cenário semelhante pode ter ocorrido quando o sistema ISBN (International Standard Book Number, ou Número padrão internacional de livro) foi atualizado de 10 para 13 dígitos. Anteriormente, a maioria dos desenvolvedores que usava o MongoDB parecia preferir criar suas próprias chaves únicas, assumindo a
Capítulo 1 ■ Introdução ao MongoDB
31
responsabilidade de garantir que o número permanecesse único. Atualmente, porém, o consenso geral parece apontar para o uso do valor de ID default que o MongoDB cria para você. Entretanto, como é o caso ao trabalhar com bancos de dados RDBMS, a abordagem escolhida se reduz principalmente à preferência pessoal. Preferimos usar um valor fornecido pelo banco de dados porque isso significa que podemos ter certeza de que a chave será única e independente de tudo o mais. Outras pessoas, conforme observamos, preferem fornecer suas próprias chaves. Em última instância, você deve decidir o que é mais apropriado para em seu caso. Se tiver certeza de que a sua chave será única (e que deverá permanecer inalterada), você deverá se sentir à vontade para usá-la. Se não estiver certo a respeito da unicidade de sua chave ou não quiser se preocupar com isso, então você poderá simplesmente usar a chave default fornecida pelo MongoDB.
Usando chaves e valores Os documentos são compostos de chaves e valores. Vamos dar outra olhada no exemplo discutido anteriormente neste capítulo: { "firstname": "Peter", "lastname": "Membrey", "phone_numbers": [ "+852 1234 5678", "+44 1234 565 555" ] }
As chaves e os valores sempre se apresentam em pares. De modo diferente de um RDBMS, em que todo campo deve ter um valor, mesmo que seja igual a NULL (de maneira, até certo ponto, paradoxal, esse valor quer dizer desconhecido), o MongoDB não exige que um documento tenha um valor em particular. Por exemplo, se você não souber o número de telefone de uma pessoa em particular em sua lista, basta simplesmente deixá-lo de fora. Uma analogia popular para esse tipo de situação ocorre com o cartão de visitas. Se você tiver um número de fax, normalmente ele será
32
Introdução ao MongoDB
colocado em seu cartão de visitas; no entanto, se não tiver um, você não escreverá: “Número de fax: nenhum”. Em vez disso, você simplesmente deixará de colocar essa informação. Se o par chave/valor não for incluído em um documento do MongoDB, será suposto que ele não existe.
Implementando coleções As coleções, de certo modo, são análogas às tabelas, porém são bem menos rígidas. Um coleção é muito parecida com uma caixa com uma etiqueta. Talvez você tenha um caixa em casa com uma etiqueta em que está escrito “DVDs”, na qual você coloque, bem, seus DVDs. Isso faz sentido, mas nada impede você de colocar CDs ou até mesmo fitas nessa caixa, se quiser. Em um RDBMS, as tabelas são rigorosamente definidas e você pode colocar somente determinados itens nelas. No MongoDB, uma coleção é simplesmente isto: uma coleção de itens semelhantes. Os itens não precisam ser semelhantes (o MongoDB é inerentemente flexível); contudo, depois que conhecermos a indexação e começarmos a ver consultas mais sofisticadas, logo você perceberá as vantagens de colocar itens semelhantes em uma coleção. Embora seja possível misturar vários itens em uma coleção, não há muita necessidade de fazer isso. Se a coleção se chamasse media, então todos os DVDs, CDs e fitas estariam no lugar certo. Afinal de contas, esses itens têm características comuns, por exemplo, um nome de artista, uma data de lançamento e um conteúdo. Em outras palavras, o fato de determinados documentos serem armazenados na mesma coleção realmente dependerá de sua aplicação. No que diz respeito ao desempenho, ter várias coleções não torna o sistema mais lento do que ter apenas uma. Lembre-se de que o MongoDB tem a ver com facilitar a sua vida, portanto você deve fazer aquilo que lhe parecer correto. Por fim, as coleções são efetivamente criadas por demanda. Especificamente, uma coleção será criada em sua primeira tentativa de salvar um documento que a referencie. Isso quer dizer que você pode criá-las por demanda (não que você deva necessariamente fazer isso). Como o MongoDB também permite criar índices e executar outros comandos de nível de banco de dados dinamicamente, você pode tirar proveito desse comportamento para criar algumas aplicações bem dinâmicas.
Capítulo 1 ■ Introdução ao MongoDB
33
Entendendo os bancos de dados Talvez a maneira mais simples de pensar em um banco de dados no MongoDB seja imaginá-lo como uma coleção de coleções. Assim como as coleções, os bancos de dados podem ser criados por demanda. Isso significa que é fácil criar um banco de dados para cada cliente – o código de sua aplicação pode até mesmo fazer isso para você. Isso pode ser feito com bancos de dados que não sejam do MongoDB também; no entanto, criar bancos de dados dessa maneira com o MongoDB é um processo bem natural. Apesar do que foi dito, somente porque você pode criar um banco de dados dessa maneira não quer dizer que você vá ou que você deva fazê-lo. No entanto, você terá essa capacidade se quiser utilizá-la.
Examinando a lista de recursos Agora que você compreende o que é o MongoDB e sabe o que ele oferece, é hora de percorrer sua lista de recursos. Uma lista completa dos recursos pode ser encontrada no site do banco de dados em www.mongodb.org/; não se esqueça de acessar esse site para obter uma lista atualizada desses recursos. A lista de recursos neste capítulo inclui muitas das atividades que ocorrem nos bastidores, mas você não precisa estar familiarizado com todos os recursos listados para poder usar o MongoDB. Em outras palavras, se você perceber que seus olhos começaram a se fechar enquanto estiver examinando essa lista, sinta-se à vontade para avançar para o final da seção!
Usando armazenamento orientado a documentos (BSON) Já discutimos o design orientado a documentos do MongoDB. Também mencionamos rapidamente o BSON. Como já vimos, o BSON faz com que seja muito mais fácil armazenar e recuperar documentos em seu formato real, eliminando, com efeito, a necessidade de qualquer tipo de mapeador ou de código especial para fazer conversões. O fato de esse recuso também fazer com que o MongoDB escale muito facilmente representa a cereja do bolo. O BSON é um padrão aberto; sua especificação pode ser encontrada em http://bsonspec.org/. Quando as pessoas ouvem falar que o BSON é
34
Introdução ao MongoDB
um formato binário do JSON, elas esperam que ele ocupe muito menos espaço que o formato JSON baseado em texto. Entretanto, isso não é necessariamente o que ocorre; na verdade, há várias situações em que a versão BSON ocupará mais espaço que o seu equivalente JSON. Você deve estar se perguntando por que o BSON deve ser usado, antes de tudo. Afinal de contas, o CouchDB (outro banco de dados eficaz, orientado a documentos) utiliza JSON puro, e é razoável se perguntar se vale a pena ter o trabalho de converter documentos de BSON para JSON e vice-versa. Em primeiro lugar, devemos nos lembrar de que o MongoDB foi criado para ser rápido e não para ser eficiente quanto ao espaço. Isso não significa que o MongoDB desperdice espaço (ele não o faz); porém um pequeno overhead para armazenar um documento é perfeitamente aceitável se isso fizer com que seja mais rápido processar os dados (o que é verdade). Em suma, o BSON é muito mais fácil de ser percorrido (ou seja, de ser analisado) e indexado rapidamente. Embora o BSON exija um pouco mais de espaço em disco que o JSON, é improvável que esse espaço extra seja um problema, pois os discos têm baixo custo e o MongoDB pode escalar usando vários computadores. O custo-benefício, nesse caso, é bem razoável: um pouco de espaço extra em disco é trocado por um desempenho melhor nas queries e na indexação. A segunda vantagem principal ao usar o BSON é que é fácil e rápido convertê-lo para um formato de dados nativo de uma linguagem de programação. Se os dados fossem armazenados em JSON puro, uma conversão relativamente de alto nível deveria ocorrer. Há drivers do MongoDB para um grande número de linguagens de programação (como Python, Ruby, PHP, C, C++ e C#), e cada um deles funciona de maneira um pouco diferente. Ao usar um formato binário simples, as estruturas de dados nativas podem ser rapidamente criadas para cada linguagem, sem a necessidade de processar inicialmente o JSON. Isso torna o código mais simples e mais rápido, alinhando-se com os objetivos estabelecidos para o MongoDB. O BSON também disponibiliza algumas extensões para JSON. Por exemplo, ele permite armazenar dados binários e incorporar um tipo específico de dado. Desse modo, enquanto o BSON pode armazenar
Capítulo 1 ■ Introdução ao MongoDB
35
qualquer documento JSON, um documento BSON válido pode não ser um JSON válido. Isso não importa, pois cada linguagem tem o seu próprio driver que converte os dados de e para BSON, sem a necessidade de usar JSON como uma linguagem intermediária. No final das contas, é pouco provável que o BSON vá ser um fator importante no modo de usar o MongoDB. Assim como ocorre com todas as grandes ferramentas, o MongoDB permanecerá silenciosamente em segundo plano e fará o que for preciso fazer. Além de possivelmente usar uma ferramenta gráfica para dar uma olhada em seus dados, em geral, você trabalhará com a sua linguagem nativa e deixará que o driver se preocupe com a persistência no MongoDB.
Suportando queries dinâmicas O suporte do MongoDB a queries dinâmicas significa que você pode executar uma query sem planejá-la com antecedência. Isso é semelhante a ser capaz de executar queries SQL em um RDBMS. Você pode estar se perguntando por que isso está listado como um recurso; certamente, é algo que todo banco de dados suporta, não é mesmo? Na verdade, não. Por exemplo, o CouchDB (que, em geral, é considerado o maior “concorrente” do MongoDB) não suporta queries dinâmicas. Isso ocorre porque o CouchDB surgiu com uma maneira totalmente nova (e, devemos admitir, empolgante) de pensar nos dados. Um RDBMS tradicional tem dados estáticos e queries dinâmicas. Isso quer dizer que a estrutura dos dados é fixada com antecedência – as tabelas devem ser definidas e cada linha deve se adequar a essa estrutura. Como o banco de dados sabe de antemão de que modo os dados estão estruturados, ele pode fazer algumas suposições e otimizações que permitam realizar queries dinâmicas e rápidas. O CouchDB inverteu esse conceito. Pelo fato de ser um banco de dados orientado a documentos, o CouchDB não tem esquemas, portanto os dados são dinâmicos. Entretanto, a ideia nova nesse caso, é que as queries sejam estáticas. Ou seja, elas devem ser definidas com antecedência, antes de serem utilizadas.
36
Introdução ao MongoDB
Isso não é tão ruim quanto possa parecer, pois muitas queries podem ser facilmente definidas previamente. Por exemplo, um sistema que permita procurar um livro provavelmente deixará que você pesquise de acordo com o ISBN. No CouchDB, você deve criar um índice que crie uma lista de todos os ISBNs para todos os documentos. Ao digitar um ISBN, a query será muito rápida, pois ela não precisará realmente procurar nenhum dado. Sempre que novos dados forem adicionados ao sistema, o CouchDB atualizará automaticamente o seu índice. Tecnicamente, uma query pode ser executada no CouchDB sem que um índice seja gerado; nesse caso, porém, o CouchDB deverá criar o índice antes de poder processar a sua query. Isso não será um problema se houver apenas uma centena de livros; no entanto resultará em um baixo desempenho se você estiver armazenando centenas de milhares de livros, pois cada query fará o índice ser gerado novamente (e novamente). Por esse motivo, a equipe do CouchDB não recomenda o uso de queries dinâmicas – ou seja, queries que não tenham sido predefinidas – em ambiente de produção. O CouchDB também permite criar suas queries como funções map e reduce. Se isso soar como algo que exija muito esforço, então você estará em boa companhia; o CouchDB tem uma curva de aprendizado, de certo modo, difícil. Para sermos justos com o CouchDB, um programador experiente provavelmente poderá compreendê-lo rapidamente; para a maioria das pessoas, porém, a curva de aprendizado será tão difícil a ponto de elas deixarem a ferramenta de lado. Felizmente, para nós, meros mortais, o MongoDB é bem mais fácil de usar. Discutiremos seu uso com mais detalhes ao longo do livro, mas aqui está uma versão resumida: no MongoDB, basta disponibilizar as partes do documento em relação às quais você deseja efetuar uma correspondência e ele cuidará do resto. No entanto, o MongoDB pode fazer muito mais. Por exemplo, você não verá problemas se quiser usar as funções map ou reduce. Ao mesmo tempo, poderá começar a usar o MongoDB facilmente; não é preciso conhecer todos os recursos avançados da ferramenta previamente.
Capítulo 1 ■ Introdução ao MongoDB
37
Indexando seus documentos O MongoDB inclui um amplo suporte à indexação de seus documentos – um recurso que realmente será prático quando estivermos lidando com dezenas de milhares de documentos. Sem um índice, o MongoDB deverá olhar cada documento individual, um de cada vez, para verificar se é algo que você deseja ver. Isso é como pedir um livro em particular a uma bibliotecária e observar enquanto ela percorre a biblioteca olhando todo e qualquer livro. Com um sistema de indexação (as bibliotecas tendem a usar a Classificação Decimal de Dewey), ela poderá encontrar a área em que está o livro que você está procurando e, rapidamente, poderá determinar se ele está lá. De modo diferente de um livro de biblioteca, todos os documentos no MongoDB são indexados automaticamente por meio da chave _id. Essa chave é considerada um caso especial, pois você não pode apagá-la; o índice é o que garante que cada valor seja único. Uma das vantagens dessa chave é que podemos ter certeza de que cada documento será unicamente identificável – algo que não é garantido por um RDBMS. Ao criar seus próprios índices, você poderá decidir se quer que eles garantam a unicidade. Se decidir criar um índice único, você poderá dizer ao MongoDB para descartar todas as duplicatas. Isso pode ou não ser o que você quer, portanto pense cuidadosamente antes de usar essa opção, pois metade de seus dados poderiam ser acidentalmente apagados. Por padrão, um erro será retornado se uma tentativa de criar um índice único com uma chave que tenha valores duplicados for feita. Há várias ocasiões em que você vai querer criar um índice que permita duplicatas. Por exemplo, se sua aplicação fizer pesquisas de acordo com o sobrenome, fará sentido criar um índice com a chave sobrenome. É claro que você não pode garantir que cada sobrenome seja único; e em qualquer banco de dados de tamanho razoável, é praticamente certo que haverá duplicatas. Contudo as capacidades de indexação do MongoDB não terminam por aqui. Ele também pode criar índices em documentos embutidos (embedded documents). Por exemplo, se diversos endereços forem armazenados na chave endereço, você poderá criar um índice com o CEP,
38
Introdução ao MongoDB
ou código postal. Isso significa que será possível recuperar facilmente um documento de acordo com qualquer código postal – e isso poderá ser feito rapidamente. O MongoDB vai um pouco além ao permitir o uso de índices compostos. Em um índice composto, duas ou mais chaves são usadas para criar um determinado índice. Por exemplo, podemos criar um índice que combine as tags lastname e firstname. Uma pesquisa pelo nome completo será muito rápida, pois o MongoDB poderá isolar rapidamente o sobrenome e, em seguida, de maneira igualmente rápida, isolar o primeiro nome. O MongoDB cuida de tudo para você no que diz respeito à indexação.
Tirando proveito dos índices geoespaciais Uma forma de indexação que vale a pena mencionar de maneira especial é a indexação geoespacial. Essa técnica nova e especializada de indexação foi introduzida no MongoDB 1.4. Esse recurso é utilizado para indexar dados baseados em localização, permitindo responder a queries do tipo quantos itens estão até determinada distância de um dado conjunto de coordenadas. À medida que um número cada vez maior de aplicações web passa a fazer uso de dados baseados em localização, esse recurso terá um papel cada vez mais importante no desenvolvimento cotidiano. Por enquanto, porém, a indexação geoespacial permanece como uma espécie de recurso relacionado a um nicho; apesar disso, você ficará muito satisfeito em tê-la disponível caso algum dia descubra que precisará dela.
Gerando perfis de queries Uma ferramenta pronta de geração de perfis (profiling) permite ver como o MongoDB descobre quais documentos devem ser retornados. Isso é útil porque, em muitos casos, uma query pode ser facilmente melhorada simplesmente por meio da adição de um índice. Se você tiver uma query complicada, e não tiver realmente certeza do motivo pelo qual ela está executando tão lentamente, o gerador de perfis de queries poderá oferecer informações extremamente valiosas.
Capítulo 1 ■ Introdução ao MongoDB
39
Atualizando informações in-place Quando um banco de dados atualiza uma linha (ou, no caso do MongoDB, um documento), ele tem algumas opções em relação ao modo de fazer isso. Muitos bancos de dados optam pela abordagem MVCC (Multi-Version Concurrency Control), que permite que vários usuários vejam versões diferentes dos dados. Essa abordagem é útil, pois garante que os dados não serão parcialmente alterados por outro programa durante uma dada transação. A desvantagem dessa abordagem está no fato de que o banco de dados precisará controlar diversas cópias dos dados. Por exemplo, o CouchDB oferece um controle bem robusto de versões, porém isso tem o custo de fazer com que os dados sejam gravados em sua totalidade. Embora esse processo garanta que os dados sejam armazenados de maneira robusta, também aumenta a complexidade e reduz o desempenho. O MongoDB, por outro lado, atualiza informações in-place (no local). Isso significa que (em oposição ao CouchDB), o MongoDB pode atualizar os dados no lugar em que eles estiverem. Normalmente, isso quer dizer que nenhum espaço extra precisará ser alocado e que os índices podem permanecer inalterados. Outra vantagem desse método é que o MongoDB realiza lazy writes (escritas preguiçosas). Ler e escrever na memória é muito rápido, porém escrever em disco é milhares de vezes mais lento. Isso quer dizer que você deve limitar a leitura e a escrita em disco o máximo possível. Isso não é possível no CouchDB porque esse programa garante que todo documento seja rapidamente gravado em disco. Apesar de essa abordagem garantir que os dados sejam gravados de forma segura em disco, ela também causa impactos significativos quanto ao desempenho. O MongoDB grava em disco somente quando for necessário, o que normalmente ocorre aproximadamente a cada segundo. Isso significa que se um valor estiver sendo atualizado várias vezes por segundo – um cenário que não será incomum se um valor estiver sendo usado como contador de páginas ou para estatísticas em tempo real – então esse valor será gravado somente uma vez, em vez de milhares de vezes, conforme seria exigido pelo CouchDB.
40
Introdução ao MongoDB
Essa abordagem torna o MongoDB muito mais rápido, mas, novamente, há uma contrapartida. O CouchDB pode ser mais lento, mas ele garante que os dados serão armazenados de forma segura no disco. O MongoDB não oferece esse tipo de garantia, e é por isso que um RDBMS tradicional provavelmente será uma solução melhor para gerenciar dados críticos como de cobrança ou de contabilidade.
Armazenando dados binários O GridFS é a solução do MongoDB para armazenar dados binários no banco de dados. O BSON suporta salvar até 4 MB de dados binários em um documento e isso deve ser muito mais que suficiente para atender às suas necessidades. Por exemplo, se você quiser armazenar uma imagem de perfil ou um clip de áudio, então 4 MB representa mais espaço do que o necessário. Por outro lado, se você quiser armazenar um trailer de filme, clips de áudio de alta qualidade ou até mesmo arquivos que tenham centenas de megabytes de tamanho, o MongoDB também tem uma solução para esses casos. O GridFS funciona armazenando informações sobre o arquivo (chamadas de metadados) na coleção files. Os dados propriamente ditos são separados em partes chamadas chunks (porções), que são armazenadas na coleção chunks. Essa abordagem faz com que o armazenamento de dados seja fácil e escalável; também torna as operações envolvendo intervalos (por exemplo, obter partes específicas de um arquivo) muito mais simples de usar. Falando de modo geral, você deve usar o GridFS por meio do driver do MongoDB para a sua linguagem de programação, portanto é improvável que você vá precisar sujar as mãos com um nível tão baixo de programação. Como tudo o mais no MongoDB, o GridFS foi projetado visando tanto à velocidade quanto à escalabilidade. Isso quer dizer que podemos estar certos de que ele estará à altura da tarefa se quisermos trabalhar com arquivos grandes de dados.
Capítulo 1 ■ Introdução ao MongoDB
41
Replicando dados Quando falamos sobre os princípios norteadores por trás do MongoDB, mencionamos que os bancos de dados RDBMS oferecem determinadas garantias para o armazenamento de dados que não estão disponíveis no MongoDB. Essas garantias não foram implementadas por vários motivos. Em primeiro lugar, esses recursos deixariam o banco de dados lento. Em segundo, eles iriam aumentar enormemente a complexidade do programa. Em terceiro, havia uma percepção de que a falha mais comum em um servidor seria de hardware, o que deixaria os dados inutilizáveis, de qualquer maneira, mesmo que eles fossem salvos em disco de forma segura. É claro que nada disso significa que a segurança dos dados não seja importante. O MongoDB não teria muita utilidade se você não pudesse contar com o fato de ser capaz de acessar os dados quando precisar deles. Inicialmente, o MongoDB oferecia uma rede de proteção com um recurso chamado replicação master-slave (mestre-escravo), em que somente um banco de dados estava ativo para escrita em um determinado instante – uma abordagem que também é razoavelmente comum no mundo RDBMS. De lá para cá, esse recurso foi substituído por conjuntos de réplicas (replica sets) e a replicação master-slave básica se tornou obsoleta e não deverá mais ser utilizada. Os conjuntos de réplica têm um servidor principal (semelhante ao master), que cuida de todas as solicitações de escrita dos clientes. Como há somente um servidor principal em um dado conjunto, pode-se garantir que todas as escritas serão tratadas adequadamente. Quando uma escrita ocorrer, ela será registrada no ‘oplog’ do servidor principal. O oplog é replicado pelos servidores secundários (pode haver vários deles) e usado para que eles se atualizem em relação ao master. Caso o master falhe em determinado instante, um dos servidores secundários se tornará o servidor principal e assumirá a responsabilidade de cuidar das solicitações de escrita dos clientes.
42
Introdução ao MongoDB
Implementando o sharding Para as pessoas envolvidas em implantação de sistemas de larga escala, é provável que o auto-sharding se prove ser um dos recursos mais significativos e mais utilizados do MongoDB. Em um cenário com auto-sharding, o MongoDB cuidará de todas as separações e recombinações de dados para você. Ele garantirá que os dados serão enviados ao servidor correto e que as queries serão executadas e combinadas da maneira mais eficiente possível. Com efeito, do ponto de vista de um desenvolvedor, não há nenhuma diferença entre conversar com um banco de dados MongoDB com uma centena de shards e conversar com um único servidor MongoDB. Esse recurso ainda não está disponível para produção; porém, quando estiver, ele levará a escalabilidade do MongoDB às alturas. Nesse meio tempo, se você estiver começando a usar o MongoDB ou estiver desenvolvendo o seu primeiro site baseado nele, provavelmente descobrirá que uma única instância dele será suficiente para atender às suas necessidades. Se você acabar criando o próximo Facebook ou a próxima Amazon, porém, ficará satisfeito por ter criado o seu site usando uma tecnologia que possa escalar de maneira tão irrestrita.
Usando as funções map e reduce Para muitas pessoas, ouvir o termo MapReduce provoca calafrios na espinha. No outro extremo, muitos defensores do RDBMS desdenham da complexidade das funções map e reduce. Para algumas pessoas, essas funções são assustadoras, pois exigem uma maneira totalmente diferente de pensar na maneira de encontrar e ordenar os dados, e muitos programadores profissionais têm problemas em entender os conceitos subjacentes às funções map e reduce. Apesar do que foi dito, essas funções oferecem uma maneira extremamente eficaz de consultar dados. Com efeito, o CouchDB suporta somente essa abordagem, que é um dos motivos pelos quais ele tem uma curva de aprendizado tão difícil.
Capítulo 1 ■ Introdução ao MongoDB
43
O MongoDB não exige que você use as funções map e reduce. De fato, o MongoDB depende de uma sintaxe simples de query, que é mais semelhante àquilo que vemos no MySQL. Entretanto o MongoDB disponibiliza essas funções para aqueles que quiserem usá-las. As funções map e reduce estão implementadas em JavaScript e executam no servidor. A função de map é encontrar todos os documentos que atendam a determinados critérios. Esses resultados são então passados à função reduce, que processa os dados. A função reduce geralmente não retorna uma coleção de documentos; em vez disso, ela retorna um novo documento que contém as informações resultantes. Como regra geral, se você normalmente usar GROUP BY no SQL, então as funções map e reduce provavelmente serão as ferramentas adequadas para realizar a tarefa no MongoDB. Nota: não pense nas funções map e reduce do MongoDB como imitações baratas da abordagem adotada pelo CouchDB. Se quiser, você poderá utilizar as funções map e reduce do MongoDB para tudo, em vez de usar o seu suporte inato a queries.
O framework de agregação do MongoDB O MapReduce é uma ferramenta bastante eficaz, porém tem uma desvantagem importante: ela não é exatamente fácil de usar. Muitos sistemas de bancos de dados são utilizados para gerar relatórios e os bancos de dados SQL em particular tornam essa tarefa bem simples. Se quiser agrupar resultados ou encontrar o valor máximo e a média, então será bem simples expressar essa ideia e obter o resultado que você estiver procurando. Infelizmente, não é tão simples fazer isso no MapReduce e você deverá fazer todas as conexões por conta própria. Com frequência, isso pode significar que uma tarefa simples será desnecessariamente desafiadora. Em resposta a isso, a MongoDB Inc (anteriormente, 10gen) acrescentou o framework de agregação. Ele é baseado em pipelines, semelhante aos comandos de piping em shells Linux, e permite encadear partes individuais de uma query para obter o resultado que você estiver procurando. Isso preserva os benefícios do design orientado a documentos do MongoDB, ao mesmo tempo que possibilita ter um bom desempenho.
44
Introdução ao MongoDB
Portanto, se precisar de toda a eficácia do MapReduce, você ainda a terá ao alcance das mãos. Se quiser somente obter algumas estatísticas básicas e processar alguns números, você gostará muito do novo framework de agregação. Você aprenderá mais sobre ele e seus comandos no capítulo 4.
Obtendo ajuda O MongoDB tem uma excelente comunidade e os principais desenvolvedores são bastante ativos e muito acessíveis; normalmente, eles se desdobram ao máximo para ajudar outros membros da comunidade. O MongoDB é fácil de usar e vem acompanhado de uma ótima documentação; entretanto é bom saber que você não está sozinho e que há ajuda disponível caso seja necessário.
Acessando o site O primeiro lugar para procurar informações atualizadas ou ajuda é o site do MongoDB (www://mongodb.org). Esse site é atualizado regularmente e contém todas as novidades sobre ele. Nesse site, você poderá encontrar drivers, tutoriais, exemplos, perguntas frequentes e muito mais.
Batendo um papo com os desenvolvedores do MongoDB Os desenvolvedores do MongoDB se encontram no IRC (Internet Relay Chat) em #MongoDB na rede Freenode (www.freenode.net). Eles residem em Nova York, mas, com frequência, podem ser encontrados batendo papo nesse canal noite adentro. É claro que os desenvolvedores precisam dormir em algum momento (o efeito do café só dura até certo ponto!); felizmente, há vários usuários experientes do MongoDB em todo o mundo, prontos para ajudar você. Muitas pessoas que acessam o canal #MongoDB não são experts; entretanto a atmosfera geral é tão amistosa que eles ficam por lá, de qualquer maneira. Por favor, sinta-se à vontade para se juntar ao canal #MongoDB e bater um papo com as pessoas que estiverem lá – você poderá encontrar ótimas dicas e sugestões. Se estiver realmente com problemas, é provável que você vá conseguir voltar ao caminho certo rapidamente.
Capítulo 1 ■ Introdução ao MongoDB
45
Copiando e colando códigos do MongoDB O Pastie (http://pastie.org) não é um site exclusivo para o MongoDB; no entanto é algo com que você irá se deparar se passar um tempo no #MongoDB. O site Pastie basicamente permite copiar e colar (daí o nome) resultados ou código de programas e então disponibilizá-los online para que outras pessoas possam vê-los. No IRC, colar várias linhas de texto pode deixá-lo confuso ou difícil de ler. Se for necessário postar uma porção razoável de texto (por exemplo, três ou mais linhas), acesse http://pastie.org, cole o seu conteúdo e, em seguida, disponibilize o link para a sua nova página no canal.
Encontrando soluções em grupos do Google O MongoDB também tem um grupo no Google chamado mongodb-user (http://groups.google.com/group/mongodb-user). Esse grupo é um ótimo lugar para fazer perguntas ou procurar respostas. A interação com o grupo também pode ser feita via email. De modo diferente do IRC, que é bem transitório, o grupo do Google é um ótimo recurso de longo prazo. Se você realmente quiser se envolver com a comunidade do MongoDB, juntar-se ao grupo é uma excelente maneira de começar.
Tirando proveito do sistema de monitoração JIRA O MongoDB utiliza o JIRA, que é um sistema para monitoração de problemas. Você pode ver o site de monitoração em http://jira.mongodb.org/, e incentivamos você a informar ativamente qualquer problema encontrado por meio desse site. Informar problemas desse tipo é visto pela comunidade como algo genuinamente positivo. É claro que você também pode fazer pesquisas nos problemas anteriores e pode até mesmo ver o roadmap e as atualizações planejadas para a próxima versão. Se você ainda não fez nenhuma postagem no JIRA, poderá fazer uma visita à sala do IRC antes. Você descobrirá rapidamente se encontrou algo novo e, em caso afirmativo, será orientado sobre como informar essa ocorrência.
46
Introdução ao MongoDB
Resumo Este capítulo ofereceu um tour guiado pelas vantagens proporcionadas pelo MongoDB. Demos uma olhada na filosofia e nos princípios orientadores por trás da criação e do desenvolvimento bem como nos compromissos assumidos pelos desenvolvedores do MongoDB ao implementar esses ideais. Também vimos alguns dos termos básicos usados em conjunto com o MongoDB, como eles se encaixam e seus equivalentes gerais no SQL. Em seguida, vimos alguns dos recursos oferecidos, incluindo como e em que situações eles poderão ser usados. Por fim, concluímos o capítulo com uma visão geral rápida da comunidade e os locais que você poderá acessar para obter ajuda caso seja necessário.