Adotando ferramentas NoSQL - Revista Java Magazine 92
Artigos Java Adotando ferramentas NoSQL - Revista Java Magazine 92
O que é NoSQL? - Parte 1
O que é NoSQL? - Parte 2
Apresentação de diversos casos de uso onde a utilização de ferramentas NoSQL são mais eficientes que um banco de dados relacional. Neste artigo também é apresentado o conceito de persistência poliglota, ou seja, a utilização, em uma única aplicação, de mais de uma ferramenta para armazenamento de dados.
Apresentar, através de casos de uso que a maior parte dos desenvolvedores já enfrentou em seu dia-a-dia, situações onde ferramentas NoSQL são mais eficientes que um banco de dados relacional.
Saber empregar adequadamente uma nova tecnologia é sempre um desafio, e com NoSQL não é diferente. Ao longo dos últimos 30 anos, bancos de dados relacionais foram a única escolha para praticamente todos os casos de armazenamento de dados de uma aplicação. Para confrontar este cenário, neste artigo são explorados casos de uso reais e comuns, onde ferramentas NoSQL podem ser empregadas de forma mais eficiente que o tradicional banco de dados relacional.
Uma das dúvidas mais comuns dos desenvolvedores em relação ao NoSQL é entender quando estas ferramentas devem ser empregadas. Responder a esta pergunta é um desafio, mas a partir de alguns casos de uso podemos apontar situações onde estas novas ferramentas podem ser mais eficientes que um banco de dados relacional.
Autenticação e autorização de usuários, armazenamento de grandes ou pequenas estruturas de árvore, dados que necessitam de flexibilidade, e armazenamento e análise de grandes volumes de dados são alguns destes casos.
Esta é a terceira e última parte de uma série de artigos que teve como objetivo cobrir o movimento NoSQL. Na primeira parte, foi apresentado o conteúdo teórico, abordando temas como história, arquiteturas e modelos de dados alternativos ao relacional. A segunda parte teve um foco bastante prático, destacando como utilizar, através da linguagem Java, algumas das principais ferramentas NoSQL.
Agora, o desafio será responder a pergunta mais frequente sobre o tema: "Quando utilizar NoSQL?". Para isso serão analisadas algumas situações reais onde a utilização de uma ferramenta NoSQL pode ser mais efetiva que o tradicional uso do banco de dados relacional. Os casos de uso abordados ao longo deste artigo exemplificam situações que praticamente todos os desenvolvedores enfrentam (ou já enfrentaram) no seu dia-a-dia.
Para finalizar esta série, será discutido o conceito de persistência poliglota, isto é, a utilização de mais de uma ferramenta para armazenamento de dados em uma única aplicação. Conceito este colocado em prática por grande parte das aplicações que adotam alguma ferramentas NoSQL.
Quando devo utilizar NoSQL?
Depois de "O que é NoSQL?" esta é sem dúvida a pergunta mais comum. No entanto, respondê-la não é uma tarefa fácil, pois o movimento NoSQL engloba diversas ferramentas com características e arquiteturas bastante distintas. E apresentar um padrão de utilização de qualquer uma delas é missão quase impossível. Portanto, não espere deste artigo um livro de receitas.
Apesar disso, existem alguns casos em que utilizar uma ferramenta NoSQL pode fazer mais sentido do que utilizar um banco de dados relacional. Este artigo traz uma compilação de alguns destes casos de uso, tendo como principal referência o material sobre anti-patterns de arquitetura criado por Gleicon Moraes, gerente de tecnologia da Locaweb e uma das principais referências internacionais de NoSQL.
Antes de iniciarmos a exploração destes casos de uso, é importante ressaltar que cada sistema é único, e adotar novas tecnologias acarretará em novos riscos a qualquer projeto. Devido a isso, antes de utilizar qualquer uma das sugestões analisadas, verifique se elas são compatíveis com o seu ambiente, pesando prós e contras de cada tecnologia.
Praticamente toda aplicação necessita lidar de alguma forma com o requisito segurança. Provavelmente este é o tema mais comum apresentado ao longo deste artigo, e é justamente por isso que iniciaremos por ele. Vale também ressaltar que segurança é algo bastante amplo e complexo, por isso vamos reduzir seu escopo e tratar apenas de dois pontos: autenticação e autorização de usuários.
Contudo, antes de iniciarmos a exploração deste tema, é importante lembrar que apesar de cada aplicação ter suas próprias características ao lidar com autenticação e autorização de usuários, existem pelo menos duas características comuns e inerentes a todas elas.
A primeira diz respeito ao ciclo de vida dos dados, que são muito acessados, mas raramente modificados. Já a segunda característica comum diz respeito ao tempo de resposta esperado, que deve ser (ou espera-se que seja) de poucos milissegundos, ou seja, os sistemas de autenticação e autorização devem prover respostas com baixa latência.
Tendo em vista estas características e a necessidade de grande parte das aplicações implementar algum mecanismo de autenticação e autorização, é possível encontrar diversas iniciativas da indústria para criar especificações, padrões ou formatos comuns para tal, dentre eles temos: JAAS (Java Authentication and Authorization Service), LDAP (Lightweight Directory Access Protocol), SAML (Security Assertion Markup Language), OAuth, OpenID, entre tantas outras.
Contudo, apesar de tantos padrões e especificações, grande parte das aplicações ainda criam soluções próprias para resolver estes problemas. Nas próximas seções iremos discutir como uma ferramenta NoSQL pode ser mais efetiva na implantação de um mecanismo mais eficiente neste cenário.
A forma mais comum de implementar uma solução "caseira" de autenticação de usuários é utilizar um banco de dados relacional para armazenar uma tabela que contenha basicamente o nome do usuário e senha, como mostra a Figura 1. O código necessário para validar usuários utilizando esta tabela também é bem simples, sendo exibido na Listagem 1.
Figura 1. Estrutura de tabela comumente utilizada para autenticação de usuários.
Listagem 1. Código comum utilizado na autenticação de usuários.
public boolean usuarioValido(String nomeUsuario, String passw) {
st = conn.prepareStatement("SELECT 1 FROM usuários WHERE usuario=? and senha=?");
st.setString(1, nomeUsuario);
st.setString(2, passw);
throw new RuntimeException("Não foi possível fechar a conexão.", e);
Apesar de funcional e bastante empregada, a solução exposta não é a ideal para este cenário. Ou seja, a utilização de um banco de dados relacional não é a forma mais eficiente de se lidar com autenticação de usuários ou qualquer operação que necessite baixa latência (milissegundos). Isso porque qualquer operação traz um overhead desnecessário com roundtrips pela rede, parsing da linguagem SQL e por fim a busca pelo dado (que pode estar na memória ou no disco).
Roundtrips: Percurso de ida e volta que um pacote de dados percorre pela rede entre o cliente e o servidor.
Parsing: Formalmente conhecida como análise sintática, é o processo de analisar uma sequência de caracteres de entrada para avaliar sua estrutura gramatical segundo uma determinada gramática formal. No entanto, pode ser empregada também como referência a todo processo de análise, que inclui a análise léxica, sintática e semântica.
Esta solução pode se tornar mais eficiente caso o banco de dados relacional seja substituído por uma ferramenta NoSQL que tenha seu modelo de dados baseado em chave-valor (para que não exista o overhead do parsing) e que os dados permaneçam primariamente na memória (o que elimina o roundtrip pela rede, tornando os resultados das consultas praticamente instantâneos).
Como apresentado na segunda parte desta série de artigos, o Redis atende perfeitamente às necessidades desta solução, pois sua estrutura de dados é baseada em chave-valor e utiliza primariamente a memória como meio de armazenamento – além de fornecer serialização em disco em paralelo.
Para substituir o banco de dados relacional pelo Redis, temos que redefinir o modo como os dados serão armazenados. Neste momento é importante lembrar que no modelo chave-valor só é permitido executar consultas pela chave e nunca pelo conteúdo armazenado (valor). Para facilitar o entendimento, pense que utilizaremos o Redis como um Map<String, String>.
Neste caso de uso precisaremos apenas de uma única chave por usuário, como mostra o modelo representado na Figura 2. A definição da chave é composta por um identificador do tipo do dado armazenado (em nosso exemplo, a String usuario), um identificador único (o nome do usuário, por exemplo porcelli) e por fim, a definição do que está sendo armazenado (a senha do usuário, definida pela String ...