Artigo no estilo: Curso
Há cerca de 40 anos os bancos relacionais vêm sendo largamente utilizados. Com uma arquitetura centralizada e um esquema de tabelas para armazenamento de dados, eles sempre foram o principal meio de armazenamento e recuperação de dados da grande maioria dos sistemas. Porém, eles foram criados em uma época em que os sistemas comumente eram construídos em apenas duas camadas: um cliente que apresentava a interface sendo utilizada pelo usuário no computador do mesmo e um banco de dados acessível através da rede fechada da empresa. Isso significa que não houve uma preocupação muito grande com os acessos simultâneos, visto que isso não ocorria naquela época.
Acontece que com a chegada da Internet e o grande número de usuários que veio com ela, esse panorama está mudando. Os sistemas, por exemplo, passaram a ser implementados em três camadas: o cliente, que utiliza navegadores web e dispositivos móveis; o servidor; e a camada de armazenamento e recuperação dos dados. O problema é que tais clientes não são mais apenas aqueles que se encontram dentro da mesma empresa. Agora eles podem estar espalhados por todo o mundo, navegando na aplicação através da Internet.
Por causa disso, grandes redes sociais como o Facebook, sistemas de busca como o Google, entre outros, vêm recebendo uma quantidade inimaginável de acesso por seus usuários e também por outros sistemas. Com o grande crescimento do acesso à internet em todo o mundo, esses sites agora precisam suportar diversos usuários durante todo o dia e em todos os dias do ano, o que os obriga a buscar pela mais alta taxa de disponibilidade.
Outro efeito colateral dessa grande quantidade de usuários é o grande volume de dados gerados pelos mesmos. Esses dados vêm sendo coletados por grandes empresas devido a seu grande valor de mercado e começam a ser utilizados como fonte de informação ao suporte de decisões estratégicas e mineração de dados. Esse novo uso faz com que ainda mais dados sejam coletados e mais espaço seja requerido para armazená-los.
Para suprir essas necessidades, tanto os sistemas quanto seus respectivos bancos de dados devem suportar a grande quantidade de acessos simultâneos, acomodar uma enorme quantidade de dados e estarem sempre disponíveis. O método comumente utilizado para que os sistemas Web suportem vários acessos simultâneos e permaneçam sempre disponíveis é o escalonamento horizontal. Ou seja, múltiplos computadores ou máquinas virtuais rodam o mesmo aplicativo e a carga de usuários é distribuída entre eles. Deste modo, em caso de atualizações, não é necessário deixar todo o sistema fora do ar, mas apenas uma máquina por vez.
No entanto, com bancos de dados relacionais, o método mais comum é o escalonamento vertical. Isso significa que ao invés de designar múltiplas máquinas para essa função, uma única máquina é utilizada e, quando preciso, investe-se no melhoramento da mesma. Em geral, investe-se em HD maior para suportar mais dados, um processador e uma conexão mais rápida para suportar o alto número de acessos simultâneos, bem como no crescimento da memória RAM. Isso acontece devido à natureza centralizada dos bancos relacionais, o que torna necessário que eles estejam em uma única máquina.
O principal problema do escalonamento vertical é a relação custo-benefício. A curva desse, nesse caso, não é linear. Assim, apesar de perceber-se bom desempenho no início, chega-se a um ponto em que maiores investimentos em hardware geram pouca melhora de performance do sistema. Além disso, as melhorias são fixas e no caso de sistemas que recebem grandes quantidades de acesso em determinados períodos de tempo, observa-se um gasto desnecessário de recursos em momentos com pouco acesso.
Para amenizar esses problemas existem algumas técnicas que possibilitam estender/prolongar o uso de bancos de dados relacionais, como sharding, desnormalização e cache distribuído. Porém, essas técnicas apenas tentam compensar as limitações destes bancos com escalonamento horizontal.
Outro problema encontrado está relacionado à natureza esquemática dos bancos de dados relacionais. Todos eles requerem que um esquema de tabelas seja previamente especificado, e todos os dados serão inseridos nessas tabelas. Caso sejam necessários novos campos, uma atualização do esquema precisará ser feita, tornando o banco de dados indisponível durante a mesma. Para tabelas com grande quantidade de dados, isso pode significar horas de indisponibilidade, o que pode afetar gravemente um sistema.
Esse esquema de tabelas também gera problemas na implementação de programas, que normalmente trabalham com a orientação a objetos. Isso porque tais objetos devem ser convertidos em múltiplas tabelas relacionadas por foreign keys em nível de banco de dados e, para recuperá-los por completo com todas as suas relações com outros objetos, diversas tabelas devem ser combinadas. Mesmo com os frameworks conhecidos que são utilizados hoje em dia, como o Hibernate, isso continua sendo um desafio, visto que as consultas complexas criadas pelos mesmos podem causar problemas de performance.
Ademais, com a grande exigência atual de se armazenar todos os tipos de dados, torna-se indispensável um modelo mais flexível de persistência, que não implique na criação de um esquema para cada nova informação a ser adicionada.
Pensando em todos esses problemas, grandes empresas como o Google, Facebook e outras criaram suas próprias soluções, as quais foram abertas à comunidade e passaram a ser conhecidas como NoSQL, da sigla Not Only SQL (Não Somente SQL). O principal objetivo desses bancos de dados é obter o tão importante escalonamento horizontal, assim como viabilizar modelos mais flexíveis de armazenamento, alta disponibilidade e suportar a alta demanda de usuários e dados.
Para tornar possível o escalonamento horizontal, todos os bancos NoSQL têm suporte a auto-sharding, o que faz com que os dados automaticamente sejam distribuídos entre os servidores sem a necessidade de participação da aplicação. Assim, novos servidores podem ser adicionados e removidos da camada de dados sem comprometer sua disponibilidade. Além disso, as operações de inserção e consulta naturalmente se espalham pelos nós do banco de dados. Outra funcionalidade também suportada pelas soluções NoSQL é a replicação de dados, o que assegura que múltiplas cópias sejam distribuídas pelo cluster, garantindo maior disponibilidade e recuperação de desastres. Com tudo isso é possível afirmar que o sistema nunca ficará offline.
Outro destaque é que mesmo com essa distribuição dos dados pelos servidores, esses bancos mantêm sua capacidade de pesquisa. Para reduzir a latência e aumentar a taxa de transferência de dados, eles possuem cache integrada, recurso que mantém em memória os dados mais acessados. Por sua vez, se um banco relacional é utilizado para algo semelhante, muito provavelmente os desenvolvedores precisarão criar essa camada de cache.
A partir de modelos de dados flexíveis, cada tipo de banco de dados NoSQL concentra-se em resolver problemas específicos. Atualmente, existem quatro categorias de soluções NoSQL, que podem ser identificadas através do formato dos dados, a saber: key-value (similar a uma hash table, armazena uma chave e seu respectivo valor), column family (as chaves apontam para múltiplas colunas, que são arranjadas em uma família de colunas), documentos (similar a key-value, com a diferença que a chave aponta para um documento, que possui uma porção de outras chaves e valores) e grafos (possibilita o armazenamento de grafos, que podem ser muito úteis em redes sociais, por exemplo).
A categoria abordada aqui será a de documentos, visto que o tema central do artigo, Couchbase, é um banco de dados que armazena primariamente documentos, apesar de também suportar o formato key-value.
Quando se busca por esse tipo de banco de dados, o mais conhecido é o MongoDB. Isso porque ele carrega certas similaridades que tornam fácil seu uso para aqueles acostumados com SQL. Como os outros bancos desse tipo, o MongoDB tem documentos como unidade de armazenamento, podendo aninhar objetos para criar documentos complexos. Esses documentos são agrupados em coleções e são pesquisáveis de forma similar às consultas feitas em bancos de dados relacionais.
Um competidor direto do tão conhecido MongoDB é o Apache CouchDB, que também tem documentos como unidade básica de armazenamento. Esse foi criado pela CouchOne Inc., que mais tarde se fundiu à Membase Inc. para criarem o Couchbase, opção que combina o modelo de dados orientado a documentos e a capacidade de indexação e pesquisa do CouchDB com a alta performance, fácil escalabilidade e alta disponibilidade do Membase.
Assim é criada a grande rivalidade entre MongoDB e Couchbase. Apesar de menos conhecido que seu rival, o Couchbase vem apresentando um grande crescimento em seu uso. A exemplo disso, temos o Viber (famoso concorrente do WhatsApp), que utilizava a combinação de MongoDB e Redis, e migrou para Couchbase puro, devido à melhor escalabilidade desse.
Outra capacidade recentemente adicionada e que vem atraindo mais usuários é a versão mobile do Couchbase. Essa versão pode ser embarcada em dispositivos móveis Android e iOS, bem como em aplicações HTML5, e permite a sincronização de dados com um banco de dados central. Com isso, é possível trabalhar offline e manter os dados atualizados, ao estabelecer uma conexão com a internet. Mais sobre isso será falado mais adiante.
Muito pode-se discutir sobre a rivalidade entre esses bancos de dados. Porém, esse não é o foco deste artigo, que visa apresentar o Couchbase e seu Java SDK. Por isso, começaremos explicando a arquitetura e funcionamento desse banco de dados.
Arquitetura do Couchbase
Para alcançar o tão almejado escalonamento horizontal o Couchbase funciona como um cluster, que nada mais é do que um grupo de nós interconectados. Neste grupo cada nó pode estar em máquinas físicas ou virtuais distintas, interconectados através da internet, e diferentemente da arquitetura comum, em que um dos nós é considerado mestre e os outros, escravos, nesse caso todos os nós são considerados iguais, não havendo hierarquia.
Do ponto de vista do desenvolvedor, no entanto, isso pode parecer estranho. Afinal, qual IP deve-se configurar como servidor do banco de dados para determinada aplicação? O que acontece é que o SDK provido para o Couchbase já trata esse tipo de problema. Ele permite a configuração de uma lista com alguns IPs de nós conhecidos. Então, o SDK tentará se conectar a um deles e, quando a conexão com qualquer um for bem-sucedida, tal nó informará ao SDK todos os nós conectados no cluster. Assim, caso um nó tenha sido adicionado ou removido, não será necessário atualizar a lista de nós manualmente na aplicação cliente. Essa lista de nós se mantém atualizada em tempo de execução à medida que novos nós são inseridos ou removidos.
Com isso, evita-se a hierarquização do cluster. A grande vantagem dessa abordagem é que não haverá um único ponto de falha. Se, por outro lado, houvesse um nó mestre e os outros fossem seus escravos, ou o cluster inteiro ficaria fora do ar, caso o mestre caísse, ou seria necessária alguma lógica para decidir um novo mestre. O objetivo dessa falta de hierarquização é tornar o banco de dados altamente disponível, possibilitando que ele continue funcionando mesmo que alguns nós venham a cair temporariamente. ...