Bancos de dados não relacionais e o movimento NoSQL
Nas grandes aplicações web é cada vez mais comum a quantidade de informações ser enorme, e ainda temos uma certeza: amanhã teremos mais dados para armanezar. Como lidar com isso de maneira eficiente?
Muito se fala ultimamente sobre os novos bancos não relacionais. Houve um encontro inicial e a segunda conferência também já aconteceu. O movimento acabou ganhando o nome de NoSQL, até mesmo por que cada banco de dados tem uma maneira diferente de se escrever queries.
A grande motivação para NoSQL é resolver o problema de escalabildade dos bancos tradicionais. Pode ser muito caro ou/e complexo escalar um banco SQL.
Esse movimento está bastante enraizado no open source. Dá para perceber isso até mesmo pelos curiosos nomes dos projetos: Voldemort, MongoDB, Tokyo Tyrant e CouchDB.
Apesar de grande quantidade desses bancos serem open source, o movimento ganhou muita força com a publicação de dois papers sobre implementações proprietárias: o Google Bigtable (que a Caelum usa atualmente) e o Amazon Dynamo. Não por acaso são duas empresas que lidam com uma quantidade enorme informações. Outros grandes nomes participam do movimento NoSQL: Yahoo! (Hadoop com HBase, Sherpa), Facebook e Digg (Cassandra), LinkedIn (Voldemort), Mixi (Facebook do Japão) (Tokyo Cabinet) e a Engine Yard (MongoDB).
Muitos acham que esses bancos de dados escalam simplesmento por causa da ausência de um schema (schema free), logo não há verificação de integridade e de relacionamentos. Mas seria só isso? O MySQL, nos seus primórdios, quando não fazia tais verificações, ainda assim não era rápido como esses novos competidores. Quais são então os segredos para tanta escalabilidade?
O Amazon Dynamo se destacou por causa da forma como o sistema escala. Cada nó no cluster comunica com outros nós (p2p) e faz ativamente parte da partição/replicação. Não tem um single-point-of-failure, mas essa facilidade de escalar não vem sem custo.
Todos os novos bancos tem em comun que eles são key-value stores, ou seja salvam, como o nome sugere, um conjunto de enradas formadas por uma chave associada a um valor e o valor poderia ser de qualquer tipo, um binário ou string que está sendo salvo de forma denormalizada (schema-free). Diferentemente dos bancos SQL não existe uma esquema forte. Essa abordagem facilita a distribuição dos dados entre vários servidores onde cada servidor possui apenas uma fatia dos dados (shard).
O CouchDB é um dos mais famosos no time dos key-value stores. Ele usa _documento_s para definir uma estrutura no banco, armazenando uma chave associada ao um documento. Um documento é apresentado como JSON. Por exemplo:
{ "Subject": "Bancos não relacionais" "Author": "Nico Stepat" "PostedDate": "10/15/2009" "Tags": ["database", "nosql", "rest"] }
Repare a estrutura dos dados é definido através da aplicação, o CouchDB não exige nada, apenas um documento JSON.
Talvez o CouchDB ficou famoso por causa da simples API REST e do uso do JSON, ou da interface grafica bonita ou por causa dos views interessantes usando Map-Reduce ou da replicação Multi-Master ou por que foi escrito em Erlang (como esse e esse também). Seja que for, a promessa principal do NoSQL - sendo escalável - o CouchDB não compriu ainda. Ele não é distribuído sozinho, e precisa de ajuda externa para tal.
Outra forma de dar alguma estrutura aos dados ficou famosa por causa do Google Bigtable. A idéia é não salvar os dados em linhas como estamos acustomados pelos bancos relacionais. Os dados serão salvos através de colunas. Veja a diferença:
Row-Oriented (3 rows presentes - Nome, Salário, Data):
João,1432.00,15/10/2009 Maria,1511.00,13/10/2009 Pedro,1721.00,01/10/2009
Column-Oriented (mesmo exemplo):
João,Maria,Pedro 1432.00,1511.00,1721.00 15/10/2009,13/10/2009,01/10/2009
No column-oriented vem primeiro TODOS os dados da primeira coluna Nome, depois a segunda coluna Salario e por último a coluna Data.
E isso altera algma coisa? Para o desenvolvedor que vai utilizar o banco de dados, a idéia é que isso seja transparente, mas para quem desenvolveu o banco, há enormes melhorias.
Isso não é muito vantajoso quando for salvo apenas um registro, como cada coluna tem que ser accessada separadamente. Também complica mais na recuperação de um registro específico (random-access) pelo mesmo motivo. Aqui a abordagem row-oriented tem vantagens.
Por outro lado, usando colunas, podemos empacotar os dados melhor já que os dados semelhantes, de mesmo formato, estão próximos um do outro. Gravando dados empacotados em BDs traz grandes vantagens, porque podemos recuperar e armanezar mais informações em menos tempo.
Com colunas também podemos aplicar projeções sobre os dados mais fácil. A segunda vantagem é importante principalmente para sistemas OLAP (online analytic process) que usam esse tipo de pesquisas pesadamente.
Banco de dados orientados a coluna vão além de um simples key-value store. Eles representam normalmente um array/hash de 4 ou 5 dimensões, usando ou adaptando o modelo proposto pelo BigTable.
Primeiramente, também temos tabelas só que eles chamem column-families. Como o nome indica um column-family são váras colunas. Quais são essas colunas, a aplicação define.
Cada coluna salva um valor. O grupo de colunas dentro de uma familia é acessível atraves de uma chave (row-key). O esquema fica:
- columnFamily - parecido com uma tabela (tabela de colunas)
- rowKey - ID do grupo de colunas
- column - nome da coluna
- value - valor a salvar