Entendendo o banco de dados NoSQL Cassandra
Autor: Nivaldo Montenegro Júnior | Publicado: 2010-07-23T14:50:00-03:00

Por necessidade, resolvi realizar testes em bancos de dados NoSQL. Estava precisando de um banco de dados que comporte pelo menos 1.5 milh&otilde;es de registros por dia e que forne&ccedil;a uma forma r&aacute;pida para realizar consultas.Testei tr&ecirc;s NoSQL: Cassandra, MongoDB e CouchDB.Criei uma pequena aplica&ccedil;&atilde;o em PHP para inserir 500 milh&otilde;es de registros (exagerei n&eacute;? Mas precisava ter certeza) e um PHP para listar a quantidade de registros. Percebi que ainda tem poucos tutoriais que mostram de forma clara como as coisas funcionam e por isso resolvi escrever alguns pequenos posts mostrando o caminho das pedras.Resolvi ent&atilde;o escrever alguns posts sobre banco de dados NoSQL com PHP.Vamos come&ccedil;ar falando sobre o Cassandra com PHP.1- Por onde come&ccedil;ar?A primeira coisa a fazer &eacute; acessar o site do projeto http://cassandra.apache.org e fazer o download do Cassandra. A vers&atilde;o que usei para os testes foi o Cassandra 0.6.3.Passos para baixar e iniciar o Cassandra:- wget&nbsp;http://ftp.unicamp.br/pub/apache/cassandra/0.6.3/apache-cassandra-0.6.3-bin.tar.gz- tar -xzvf apache-cassandra-0.6.3- cd apache-cassandra-0.6.3- ./bin/cassandra -fDepois desses comandos o Cassandra estar&aacute; funcionando com as configura&ccedil;&otilde;es padr&atilde;o. Mas antes de come&ccedil;armos a usar &eacute; necess&aacute;rio entenderemos a estrutura desse banco de dados NoSQL. Pra quem &eacute; acostumar com bancos de dados tradicionais, &eacute; necess&aacute;rio um pouco de esfor&ccedil;o para a quebra de parad&iacute;gma.2- Conhecendo a estrutura do CassandraO Cassandra &eacute; um banco de dados NoSQL e armazena as informa&ccedil;&otilde;es no formato chave = valor, mas para quem est&aacute; acostumado com bancos de dados tradicionais, tabelas, joins, normaliza&ccedil;&atilde;o, etc., &eacute; dif&iacute;cil colocar na cabe&ccedil;a que tudo o que voc&ecirc; aprendeu a vida toda foi por &aacute;gua abaixo. :)Li v&aacute;rios artigos e tutoriais para entender o esquema de armazenamento e indexa&ccedil;&atilde;o do Cassandra. Um excelente ponto de partida &eacute; este artigo:&nbsp;WTF is a SuperColumn? An Intro to the Cassandra Data Model.Pra quem n&atilde;o sabe o que significa WTF: What the fuck... ou seja, que porra &eacute; uma supercolumn?!?! :)Com este artigo d&aacute; para entender bem o funcionamento do esquema de armazenamento e indexa&ccedil;&atilde;o, por isso, n&atilde;o explicarei detalhadamente como funciona, apenas superficialmente atrav&eacute;s de exemplo para complementar o artigo citado.De forma bem simplificada:- Column: Armazena chave, valor e timestamp. Todos os dados s&atilde;o armazenados em columns. A column n&atilde;o precisa ser criada em arquivo de configura&ccedil;&atilde;o, basta inserir uma nova column com chave/valor que o banco de dados cria automaticamente. Column - ['id']['chave'] = ['valor']- SuperColumn: Armazena chave = chave/valor/timestamp. &Eacute; como se fosse um conjunto de columns. A SuperColumn na verdade &eacute; uma ColumnFamily do tipo Super. Possui duas chaves. SuperColumn - ['id']['chave1']['chave2'] = valor- ColumnFamily: &Eacute; uma fam&iacute;lia de colunas, ou seja, &eacute; o agrupamento de v&aacute;rias chave = valor. &Eacute; necess&aacute;rio criar a ColumnFamily dentro das configura&ccedil;&otilde;es do cassandra (storage-conf.xml). Ou seja, as Columns ficam armazenadas em uma ColumnFamily.Exemplo:ColumnFamily: Usuarios['junior']['login'] = ['junior'] ['junior']['nome'] = ['Nivaldo'] ['junior']['sobrenome'] = ['Montenegro'] ['junior']['email'] = ['nivaldomjunior@gmail.com'] ['usuario2']['login'] = ['usuario2'] ['usuario2']['nome'] = ['Fulano'] ['usuario2']['sobrenome'] = ['de tal'] ['usuario2']['email'] = ['fulano@gmail.com'] ['usuario2']['fone'] = ['(83)1234-1234']&nbsp;&nbsp;Usuarios = { // ColumnFamily &nbsp;&nbsp; &nbsp;junior: { &nbsp; // Esta &eacute; a chave da CF (id) &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// Dentro da CF podemos ter um n&uacute;mero infinito de chave/valor &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;login: "junior", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;nome: "Nivaldo", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;sobrenome: "Montenegro", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;email: "phatduckk@example.com", &nbsp;&nbsp; &nbsp;}, // Fim &nbsp;&nbsp; &nbsp;usuario2: { &nbsp; // Esta &eacute; a chave para outra linha na CF (id) &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// Podemos inserir outro n&uacute;mero infinito de chave/valor e n&atilde;o precisa ter as mesmas chaves/valor que outras linhas da CF &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;login: "junior", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;nome: "Nivaldo", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;sobrenome: "Montenegro", &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;email: "phatduckk@example.com",&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; fone: "(83) 1234-1234" &nbsp;&nbsp; &nbsp;}, }- KeySpace: &Eacute; um conjunto de ColumnFamily. Analogamente, &eacute; como se fosse um banco de dados criado dentro do cassandra. &Eacute; necess&aacute;rio realizar configura&ccedil;&otilde;es no arquivo storage-conf.xml para criar as KeySpaces e realizar um restart no Cassandra.Evoluindo o exemplo dado para a ColumnFamily, podemos transformar a ColumnFamily em uma SuperColumn e termos dados mais organizados sobre os clientes.Exemplo SuperColumn:Exemplo:SuperColumn: Agenda['junior']['amigo1']['nome'] = ['Amigo 1']['junior']['amigo1']['telefone'] = ['(88)1234-1234']['junior']['amigo2']['nome'] = ['Amigo 2']['junior']['amigo2']['telefone'] = ['(99)4312-4312']['usuario2']['amigox']['nome'] = ['amigox']['usuario2']['amigox']['telefone'] = ['(77)9987-0987']['usuario2']['amigoy']['nome'] = ['Amigo y']['usuario2']['amigoy']['email'] = ['fulano@gmail.com']['usuario2']['amigoy']['fone'] = ['(83)1234-1234']&nbsp;Agenda = { // SuperColumn&nbsp;&nbsp; &nbsp;junior: { &nbsp; // ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;amigo1: { //Chave da ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Dentro da CF podemos ter um n&uacute;mero infinito de chave/valor&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nome: "Amigo 1",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;telefone: "(88)1234-1234",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;} //Fim do amigo1&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;amigo2: { //Outra chave na ColumnFamily&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nome: "Amigo 2",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;telefone: "(99)4312-4312",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;} // Fim do amigo 2&nbsp;&nbsp; &nbsp;}, // Fim da CF junior&nbsp;&nbsp; &nbsp;usuario2: { &nbsp; // Outra ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;amigox: { //Chave da ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Podemos inserir outro n&uacute;mero infinito de chave/valor e n&atilde;o precisa ter as mesmas chaves/valor que outras linhas da CF&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nome: "amigox",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;telefone: "(77)99870987",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;} //Fim amigox&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;amigoy: { //Outra CF&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nome: "Amigo Y",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fone: "(83)1234-1234"&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;email: "fulano@gmail.com",&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;} //Fim amigoy&nbsp;&nbsp; &nbsp;}, //Fim da CF usuario2}Ou seja, temos os seguintes n&iacute;veis no Cassandra:KeySpaces&nbsp;&nbsp; &nbsp;ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; Columns&nbsp;&nbsp; &nbsp;SuperColumn&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ColumnFamily&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Columns&nbsp;Um fato importante &eacute; que as buscas necessariamente precisam ser realizadas usando os &iacute;ndices, ou seja, as chaves das ColumnFamilys. N&atilde;o tem como fazermos as consultas usando os valores finais das chaves diretamente no banco de dados. Para isso &eacute; necess&aacute;rio buscarmos todos os dados e realizarmos a consulta usando a linguagem de programa&ccedil;&atilde;o. Por isso, &eacute; extremamente importante criar &iacute;ndices que realmente sejam utilizados e n&atilde;o usar n&uacute;meros sequencias como costumamos fazer nos campos id das tabelas em um banco de dados tradicional.3- Configurando o cassandra para atender o exemplo acima&Eacute; necess&aacute;rio configurar o Cassandra para criar as KeySpaces, ColumnFamilys e SuperColumns (ColumnFamily do tipo Super) que iremos precisar para armazenar os nossos dados. As configura&ccedil;&otilde;es s&atilde;o relativamente simples, mas precisamos definir qual o tipo de ordena&ccedil;&atilde;o que faremos para cada ColumnFamily e SuperFamily, pois os dados s&atilde;o armazenados e ordenados automaticamente de acordo com a configura&ccedil;&atilde;o criada para a ColumnFamily ou SuperColumn.Exemplo de configura&ccedil;&atilde;o:&nbsp;&nbsp; &nbsp;&lt;Keyspace Name="Teste"&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&lt;!-- Defini&ccedil;&atilde;o da ColumnFamily --&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&lt;ColumnFamily CompareWith="UTF8Type" Name="Usuarios"/&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&lt;!-- Defini&ccedil;&atilde;o da SuperColumn --&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&lt;ColumnFamily CompareWith="UTF8Type" Name="Agenda"&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CompareSubcolumnsWith="UTF8Type" ColumnType="Super"/&gt;&nbsp;&nbsp; &nbsp;&lt;/Keyspace&gt;O par&acirc;metro CompareWith nas ColumnFamilys &eacute; o que vai determinar a forma de ordena&ccedil;&atilde;o da ColumnFamily. O CompareWith no nosso exemplo vai ser usado para ordenar a chave da ColumnFamily, que no nosso exemplo tem dois valores: junior e usuario2. No artigo citado acima (esse link) tem um exemplo bem detalhado sobre a forma de ordena&ccedil;&atilde;o.J&aacute; nas SuperColumns, o par&acirc;metro CompareWith ordena o nome da ColumnFamily, no nosso exemplo os valores junior e usuario2, e o par&acirc;metro CompareSubColumnsWith ordena a chave da ColumnFamily, que no nosso exemplo tem os valores amigo1, amigo2, amigox e amigoy.4- Conclus&atilde;oO Cassandra &eacute; um banco de dados NoSQL extremamente flex&iacute;vel e poderoso, principalmente quando se pensa em escalabilidade, mas a organiza&ccedil;&atilde;o dos dados &eacute; o que vai determinar o sucesso da utiliza&ccedil;&atilde;o desse tipo de banco de dados. &Eacute; necess&aacute;rio realizar um trabalho minucioso em cima dos &iacute;ndices para que as buscas sejam realmente r&aacute;pidas e eficientes, minimizando a filtragem de dados usando a linguagem de programa&ccedil;&atilde;o.Espero que eu tenha esclarecido as suas d&uacute;vidas e no pr&oacute;ximo post vou falar um pouco sobre como utilizar o Cassandra com PHP em um servidor com Debian.&nbsp;