Conteúdo


Desenvolvendo aplicativos móveis com Node.js e MongoDB, parte 1

Os métodos e resultados de uma equipe

Acelerando o tempo de retorno dos sistemas de engajamento

Comments

Conteúdos da série:

Esse conteúdo é a parte # de # na série: Desenvolvendo aplicativos móveis com Node.js e MongoDB, parte 1

Fique ligado em conteúdos adicionais dessa série.

Esse conteúdo é parte da série:Desenvolvendo aplicativos móveis com Node.js e MongoDB, parte 1

Fique ligado em conteúdos adicionais dessa série.

O desenvolvimento de nuvem e móvel mudaram drasticamente a maneira como as empresas operam e se conectam com os clientes. As empresas cada vez mais buscam soluções de backend que sejam fáceis de escalar, prontas para implementações de nuvem e móveis e rapidamente produzidas.

Embora o Java ainda seja o padrão para o desenvolvimento de aplicativos corporativos e nuvem, há uma forte pressão no setor para reduzir a quantidade de alternância de contexto ao desenvolver aplicativos. Com os conceitos de design do MobileFirst na liderança, os desenvolvedores estão começando com uma abordagem “de fora para dentro” do desenvolvimento. Em virtude de o design “de fora para dentro” começar com o usuário, a interface com o usuário está proeminentemente à frente. Uma das bases para o desenvolvimento de UIs é o JavaScript. Ao poder começar com o JavaScript no cliente e, em seguida, ser capaz de reutilizar essas mesmas qualificações em JavaScript no servidor (tanto o Node.js como o MongoDB são baseados em JavaScript), há uma redução significativa na quantidade de alternância de contexto entre as diversas linguagens de programação que o desenvolvedor precisa compreender. Com os pesos-pesados do mercado como Walmart, General Motors e LinkedIn abertamente adotando e defendendo o Node, o Node.js parece ir com força total para a empresa, juntamente com o Java, como uma plataforma de aplicativo corporativo.

A equipe do Extreme Blue do laboratório da IBM em RTP, NC, foi desafiada a desenvolver um backend completo no Node.js para o IBM Passes. A equipe o desenvolveu com sucesso em 40% menos de tempo do que o exigido por uma solução Java alternativa, oferecendo a mesma funcionalidade. Ela também realizou testes de desempenho abrangentes que demonstraram a escalabilidade mais fácil e a melhor utilização de hardware do backend do Node.js (em comparação com o Java).

Esse artigo apresenta os principais recursos e vantagens do Node.js usado com o MongoDB. Você aprenderá sobre os tipos de soluções mais adequados para a produção do Node.js, bem como as vantagens e desvantagens dela.

Desenvolvedores familiarizados com os conceitos básicos dos serviços da web RESTful, JSON, JavaScript e Node.js aproveitarão ao máximo esse artigo.

 

IBM Passes

IBM Passes é uma solução desenvolvida com base no Apple Passbook, que foi lançado pela Apple no final de 2012. O Apple Passbook é um aplicativo que permite que os usuários convenientemente armazenem em um lugar cartões de embarque, ingressos de cinema, cupons de varejo, cartões de fidelidade e outros materiais para o engajamento do cliente (chamados de passes). A Apple lançou o aplicativo juntamente com especificações para os passes. No entanto, ela não forneceu uma forma de as empresas criarem e gerenciarem esses passes. IBM Passes resolve esse problema. Ele contém um serviço da web RESTful que fornece uma API que outros aplicativos podem consumir. Esse serviço interage com o Push Notification Service da Apple por meio do IBM PushWorks e lida com a analítica usando o IBM WebSphere® Analytics Platform.

A IBM criou um frontend para esse serviço, que permite que os usuários criem, atualizem e distribuam passes. Esse frontend é chamado de Pass builder, mostrado na Figura 1. O Pass builder é uma solução HTML/JavaScript que se baseia na interface RESTful do backend do Passes. Para encontrar mais informações sobre o Pass builder, consulte a introdução abrangente ou a introdução breve e o vídeo.

Figura 1. Interface do IBM Pass builder

A implementação atual do backend do IBM Passes usa servlets Java para acessar o DB2. Com essa solução, os documentos JSON são armazenados como sequências de caracteres no banco de dados relacional do DB2. Isso requer a serialização e a desserialização de todas as transações que envolvem esses documentos JSON e leva a uma sobrecarga adicional. Além disso, as propriedades de consulta desses documentos se tornam mais complexas na medida que o aninhamento fica mais profundo.

Uma alternativa ao Java: uma pilha de tecnologia do Node.js e MongoDB

Nosso projeto estava focado em uma implementação alternativa do backend RESTful para a solução IBM Passes. Nós usamos uma pilha de tecnologia completamente diferente: Node.js e MongoDB. Isso nos permitiu substituir a implementação de Java ainda mantendo o suporte ao cliente de frontend. Nossa implementação fornece o mesmo conjunto de APIs que a implementação de Java. Como resultado, ele é intercambiável como um backend para o cliente do Pass builder.

Além de recriar a funcionalidade da versão Java, realizamos testes de desempenho abrangentes nos dois aplicativos. Além disso, a pilha de tecnologia que usamos nos permitiu implementar as funcionalidades principais no tempo de desenvolvimento de três semanas em comparação com as cinco semanas da equipe do Java (40% de redução no tempo de retorno). Optamos por usar essa pilha de tecnologia por diversos motivos:

  • Especificação do Apple Passbook (estritamente JSON)
  • Serviço da web RESTful com o JSON sendo o formato de troca de dados primário
  • JavaScript Everywhere (frontend, backend e armazenamento de dados)

Por que escolhemos o Node.js

O Node é um tempo de execução de servidor da web JavaScript. Como ele usa JavaScript, os desenvolvedores do frontend podem trabalhar na mesma linguagem que os desenvolvedores do backend. Esse conceito é chamado de JavaScript Everywhere. Na prática, esse conceito unifica os esforços de desenvolvimento ao reduzir o número de diferentes conceitos que os desenvolvedores devem compreender. Além disso, o formato de troca de dados mais usado, JSON, pode ser analisado de forma nativa pelo frontend e pelo backend. Essa é outra maneira em que a sobrecarga de processamento pode ser reduzida por meio da simplificação da serialização. Além do benefício de usar uma linguagem de script, o ambiente de execução leve do Node permite o desenvolvimento e implementação rápidos. Como resultado, o Node é uma solução eficiente para o desenvolvimento ágil, em que a iteração normalmente envolve trabalhar em fatias verticais.

Tablela 1. Principais conceitos de tecnologia usados para o IBM Passes
Frontend do Pass builderBackend do Passes
JavaScriptJava
Node.jsContêiner do Servlet
MongoDBDB2
JSONSQL
JSON

O Node contém recursos que suportam as cargas de trabalho da web moderna: trocas de dados estruturados pequenas e frequentes. Isso torna o Node perfeito para sistemas de engajamento. Em outras palavras, ele é um candidato ideal para aplicativos que envolvem trocas de informações em vez de processos computacionais. Do ponto de vista técnico, isso significa escolher o Node para aplicativos dependentes de E/S em vez de para os dependentes de CPU. IBM Passes é um exemplo perfeito de tal aplicativo. As únicas operações computacionalmente caras são a assinatura criptográfica e a compactação (zipar). O restante do aplicativo envolve a troca dos recursos de imagem e dados JSON.

O Node se diferencia da maioria dos tempos de execução de aplicativos da web na maneira que ele lida com a simultaneidade. Em vez de usar o encadeamento para obter a simultaneidade, o Node utiliza um loop acionado por eventos sendo executado em um único processo. O Node suporta um modelo assíncrono (sem bloqueio), enquanto tecnologias como o Java suportam um modelo síncrono (com bloqueio). Para esclarecer as principais diferenças entre esses dois conceitos, considere a seguinte metáfora do restaurante:

Modelo assíncrono

Pense em um aplicativo da web como um restaurante e suas solicitações recebidas como os clientes fazendo pedidos. Um aplicativo assíncrono permitiria que um único garçom atendesse a vários clientes ao mesmo tempo. O garçom atenderia aos clientes conforme os pedidos fossem concluídos. No tempo de inatividade, o mesmo garçom cuidaria e novos pedidos dos clientes.

Modelo síncrono

Um “restaurante” síncrono dedicaria um único garçom a um único cliente do início até a conclusão de seu pedido. Como resultado, o restaurante precisa de uma quantidade de garçons igual à de clientes. Além disso, haveria momentos em que os garçons esperariam enquanto outro trabalho poderia ser realizado.

A diferença ilustrada por essa metáfora é simplesmente o mecanismo usado para obter a simultaneidade. O Java faz isso com encadeamentos, enquanto o Node usa um loop de eventos. O resultado é que o Java deve sofrer uma sobrecarga adicional na alternância de contexto entre os encadeamentos. Em outras palavras, mais encadeamentos significam mais tempo gasto comutando contextos e menos tempo trabalhando nas solicitações recebidas. Isso torna o ajuste de escala de um aplicativo Java mais caro.

O Node suporta E/S assíncronas, com base em eventos como a conclusão de uma operação de leitura de arquivo ou consulta de banco de dados. Esses eventos são tratados com funções de retorno de chamada, que permitem que o aplicativo prossiga enquanto a E/S está sendo realizada. O loop de eventos trata desses eventos. Para encontrar mais informações sobre o loop de eventos, consulte o “Node.js para desenvolvedores Java”, um artigo do developerWorks escrito por Andrew Glover.

Por que escolhemos o MongoDB

O MongoDB é um banco de dados orientado a documentos criado para facilitar o desenvolvimento e ajuste de escala. A capacidade de armazenar objetos JavaScript nativamente do MongoDB economiza tempo e energia de processamento. Em vez de uma linguagem específica de domínio como o SQL, o MongoDB utiliza uma interface JavaScript simples para realizar consultas. Consultar um documento é tão simples como passar um objeto JavaScript que descreve parcialmente o destino da pesquisa.

O MongoDB foi uma excelente solução para o nosso domínio do problema, porque, como mencionado, a especificação do Passbook da Apple é altamente dependente do JSON. Na verdade, os passes em si são descritos como objetos JSON. Como resultado, armazená-los como estão com o MongoDB é uma abordagem melhor que reduzir a estrutura JSON semicomplexa em várias relações em um banco de dados relacional (como o DB2).

Comparativo

Quisemos comparar nossa implementação do Node do IBM Passes com sua versão Java. Decidimos comparar o desempenho de ponta a ponta dos dois aplicativos, com a métrica de interesse, em última análise, sendo os tempos de resposta das solicitações de HTTP realizadas para os diversos endpoints da API. O objetivo principal dessa abordagem era capturar o desempenho de toda a pilha por trás de cada solução. Ao considerar variáveis como rede e sistema operacional, obtivemos uma comparação objetiva dos dois aplicativos. Além disso, acreditamos que os tempos de resposta de ponta a ponta eram um reflexo melhor de uma experiência do usuário real do que uma análise mais granular como a cronometragem de consultas de bancos de dados ou a cronometragem de funções individuais.

Metodologia

Para fins de comparação dos dois aplicativos, escrevemos um wrapper do Node com base no Apache Benchmark, uma ferramenta de linha de comandos de comparação HTTP. A partir daí, criamos uma estrutura de comparação executada em relação a definições de teste genéricas e resultados gerados. O Apache Benchmark nos forneceu o tempo de resposta médio, seu desvio padrão, o número de solicitações concluídas por segundo, o número de respostas com falha (não 200), o número de erros do servidor e o número de tempos limite. Os parâmetros foram o nível de simultaneidade, o número de solicitações e a configuração da solicitação. Incluímos definições de teste e funções de configuração nessa estrutura e prosseguimos para a comparação de nosso aplicativo.

Cuidamos da parte dos conjuntos de ferramentas de nosso processo de comparação. O ambiente de teste é de igual, se não de maior, importância devido à abordagem científica desejada deste processo. Decidimos usar o OpenStack para imitar um ambiente de nuvem. Configuramos instâncias idênticas para o aplicativo Node, para o aplicativo Java e para o aplicativo de geração de carga. Cada instância recebeu um processador quad core de 2,4 GHz (virtual), 8 GB de RAM (virtual) e 80 GB de armazenamento. A Figura 2 mostra a topologia da implementação do OpenStack usada.

Figura 2. Topologia de implementação do OpenStack

Essas instâncias foram configuradas com a mesma imagem base (Ubuntu Server 12.04 64 bits). Além disso, foi instalado apenas o software necessário para executar e monitorar os aplicativos. No que se refere à configuração do tempo de execução, usamos a configuração padrão para o Node (a mesma em que o Chrome V8 Engine se baseia).

Consultamos a equipe do Java em relação à configuração do tempo de execução do JRE e usamos as configurações padrão para o contêiner do servlet e para o DB2. Nós reconhecemos que configurações adicionais poderiam potencialmente melhorar o desempenho do backend. No entanto, isso também é verdade para o tempo de execução do Node e perde a importância. Nosso propósito é provar que ele atende aos critérios de desempenho e pode ser escalado horizontalmente em vez de verticalmente, além de facilitar o desenvolvimento ágil.

As tarefas de comparação foram enfileiradas manualmente por meio da interface da web da instância do gerador de carga ou como resultado de alterações na base do código. A comparação prosseguiu no ambiente OpenStack. Definimos uma tarefa de comparação como a execução de todos os suítes de testes (como grupos de execuções de endpoint da API) considerando os parâmetros de nome da ramificação, nível de simultaneidade e total de solicitações a serem feitas. Dentro de uma comparação, um conjunto fixo de endpoints da API foi testado pela ferramenta de comparação. Esses testes foram executados sequencialmente (isto é, sem sobrepor o tráfego). Além disso, as comparações (grupos de testes) foram executadas sequencialmente pelo mesmo motivo.

Resultados

Nosso caso de teste demonstrou que a implementação do Node e do MongoDB apresentou tempos de resposta mais rápidos quando o nível de simultaneidade excedeu 50. Podemos atribuir isso à natureza dependente de E/S do aplicativo Passes. Abaixo do nível de simultaneidade de 50, o aplicativo Java foi mais rápido, pois o aplicativo foi degradado de dependente de E/S para dependente de CPU sob a carga reduzida. Com níveis de simultaneidade maiores, a instância única do Node claramente superou a instância Java/DB2 para todas as chamadas de API.

Figura 3. Resultados de desempenho (calculando os endpoints “mais rápidos” por aplicativo)

Para comparar a utilização de hardware da implementação do Node vs. de Java, foi necessário definir o perfil das instâncias em que os dois aplicativos estavam sendo executados. Para esse propósito, usamos dois aplicativos de coleta de estatística populares: CollectD e StatsD. A instalação do CollectD em nossas instâncias introduziu uma sobrecarga insignificante e tornou o uso de disco, memória e CPU transparente. Usamos o StatsD na instância de monitoramento para coletar essas estatísticas. O Graphite foi usado na mesma instância para visualizar os dados de séries temporais como gráficos apresentados em um formato de painel.

Pudemos correlacionar cada comparação com os dados de utilização de hardware das séries temporais. Embora tenhamos valores de uso médios para o uso de CPU e memória durante a comparação de cada endpoint, achamos mais útil mostrar as tendências gerais. A Figura 4 mostra essas métricas ao longo do período de tempo de uma comparação de longa duração. O aplicativo Node usou, em média, menos memória e uma porcentagem do CPU menor. O baixo uso de CPU pode ser interpretado como um resultado da natureza dependente de E/S do aplicativo.

Figura 4. Resultados de desempenho da comparação da utilização de hardware

Conclusões

Embora o Node possa não ser a panaceia para todos os desafios da web moderna, ele é perfeito para as demandas dos sistemas de engajamento. O Node foi projetado especificamente para aplicativos dependentes de E/S e trocas de informações frequentes. Seu ambiente de execução leve permite o desenvolvimento ágil e a iteração imediata. Como demonstrado em nosso caso de teste do IBM Passes, o Node levou a uma redução de 40% no tempo de retorno enquanto nos permitiu dobrar o tráfego atendido com metade dos servidores (em comparação com a implementação de Java). Dessa forma, o Node pôde fornecer as mesmas funcionalidades que o Java e superou o Java em termos de desenvolvimento rápido e melhor utilização de hardware.

Agradecimentos

Agradecimentos especiais para nossos mentores, cuja sabedoria e experiência nos orientaram durante nosso estágio: Joshua A. Alger, Andy Dingsor, Curtis M. Gearhart, Christopher Hambridge e Todd Kaplinger. Um enorme obrigado a Ross Grady, RTP Lab Manager do IBM Extreme Blue, cuja paciência e esforço para a melhoria contínua garantiu nosso sucesso. Gostaríamos também de expressar nossa gratidão a Jeff Jagoda por sua experiência em Node.js e inestimável feedback.


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Desenvolvimento móvel, Tecnologia Java
ArticleID=969643
ArticleTitle=Desenvolvendo aplicativos móveis com Node.js e MongoDB, parte 1: Os métodos e resultados de uma equipe
publish-date=04252014