Arquitetura de micro serviços em Node.js + MongoDB

Até o presente momento eu já escrevi alguns artigos aqui no blog sobre a arquitetura de micro serviços (microservices architecture), uma proposta de arquitetura antagônica aos tradicionais monolitos, ou grandes blocos de software que são o tipo mais comum de arquitetura presente atualmente nas empresas. Eu já estudava e gostava bastante deste modelo de arquitetura, que não é exatamente nova mas uma releitura de arquiteturas passadas, mas depois de passar a trabalhar no Agibank e ver os ganhos que temos com esta abordagem no dia-a-dia eu realmente fui convertido em um evangelista de micro serviços nas empresas. 🙂

Resumidamente um micro serviço é uma API, um backend que responde a uma única e exclusiva função, pautado no clássico SRP do SOLID (Single Responsibility Principle – Princípio da Responsabilidade Única). Cada micro serviço é independente dos outros e não possui qualquer tipo de dependência, tendo até mesmo a sua própria base de dados e servidor web em muitos casos, uma vez que esse é o único cenário real de 100% independência.

Obviamente sendo tão “micro” em sua responsabilidade, pouco se faz com apenas um microservice em um sistema inteiro, assim, é na chamada a múltiplos micro services que os comportamentos dos sistemas complexos são construídos, pautados em princípios como tolerância à falhas, containerização e escala horizontal. A Amazon é um símbolo desta proposta uma vez que alegam ter mais de 100 micro serviços sendo chamados durante a exibição de suas páginas de produtos no site Amazon.com. Outro ícone desta abordagem é a Netflix, que tem um serviço responsável por tentar derrubar seus micro serviços de maneira aleatória para testar sua resiliência, tolerância à falhas e interdependência entre eles.

E por fim, temos os testes e o deploy. É incrivelmente mais fácil ter uma cobertura de testes unitários automatizados que garantam o funcionamento de um sistema completo se eu tiver quebrado ele em micro-pedaços, assim como o deploy, que se torna bem menos oneroso e mais ágil neste contexto, podem fazer implantação de microservices de maneira independente desde que os contratos sejam mantidos intactos ou através de um sistema rigoroso de versionamento e APIs.

Ok, mas esta teoria eu já falei em outras oportunidades aqui no blog, certo? Mas como se cria um microservice na prática?

A ideia deste artigo é justamente é essa, mostrar como você cria um microservice profissional usando a plataforma do Node.js, uma das mais utilizadas neste tipo de abordagem (Netflix, LinkedIn, PayPal, etc). Em Java você poderia fazer algo semelhante também, usando Spring Boot, mas deixo isso para outra oportunidade.

Por que Node.js?

Lembra quando falei que a ideia é que o micro serviço seja independente do restante da aplicação? Pois é, uma das coisas que te garante independência é ter microservices rodando de maneira standalone, ou seja, em suas próprias plataformas.

Rodar microservices em Node.js permite que cada um deles tenha a sua própria instância de Node sem que isso pese muito no custo da empresa, uma vez que rodar Node é extremamente barato. Além de ser extremamente rápido de criar serviços standalone em Node, seja a partir do clássico exemplo de servidor em 12 linhas que está no site oficial ou usando web frameworks como ExpressJS (meu favorito).

Caso não esteja familiarizado com Node.js, ExpressJS e cia., recomendo ler os outros posts aqui do blog ou meu livro.

Por que MongoDB?

Idealmente cada serviço tem o seu próprio banco de dados, para que seja realmente independente dos demais. Sendo o domínio de aplicação extremamente enxuto, o banco de dados do microservice também o será. Uma coisa que eu acho extremamente positiva no uso de microservices com bancos independentes, principalmente em empresas que usam métodos ágeis, é que cada serviço pode ter a tecnologia de banco de dados mais adequado para sua função.

Assim, um microservice de catálogo de produtos pode usar MongoDB, enquanto que no mesmo sistema, o microservice de pagamento pode usar um SQL Server, enquanto que os sistemas estatísticos da empresa estão em um Cassandra. Óbvio que manter uma estrutura dessas em pé requer um time de engenharia forte, mas esse tipo de liberdade permite que os serviços sejam o mais eficiente possíveis e que os times que trabalham neles não fiquem presos a uma única suíte tecnológica, sendo autônomos e auto-organizados como o ágil prega.

Neste contexto, MongoDB é uma excelente opção na minha opinião, uma vez que sua natureza já prega a independência dos dos documentos mesmo entre as coleções do mesmo banco. Assim, conseguimos criar bancos poderosos, que escalam muito bem horizontalmente (um requisito muito comum em abordagens de micro serviços) e ao mesmo tempo simples, geralmente tendo uma coleção apenas.

Eu particularmente sou suspeito pra falar (afinal sou autor de livros sobre ambas plataformas), mas acho que Node e Mongo tem um fit absurdamente bom para compor soluções. Se você não sabe nada de MongoDB, sugiro ler os outros posts sobre o assunto aqui no blog ou o meu livro.

O que não abordarei?

Não falarei de DevOps aqui e consequentemente de deploy, CI, CD, etc. Quero me ater ao desenvolvimento do micro serviço sem ter de explicar Docker, API Gateway, etc.

Não falarei de front-end aqui. Ok, isso é meio óbvio, mas realmente não teremos interface gráfica neste tutorial. Primeiro porque não é meu intuito, segundo que não sou reconhecido pelos meus talentos com frameworks front-end. 😉

Não falarei dos princípios de desenvolvimento de web APIs RESTful, o que sugiro que você busque em outros materiais aqui do blog ou em meu livro de Programação Web com Node.js. Mas sim, usaremos estes princípios ao longo deste artigo.

Não falarei de versionamento ou documentação de APIs também (Swagger por exemplo).

Case de Exemplo: Cinema

Imagine que você está trabalhando no departamento de TI de uma grande rede de cinemas (ideia nem um pouco original, admito) que deseja refatorar todo o seu sistema de bilheteria e bomboniere de um gigantesco monolito para uma arquitetura de micro services. Como essa empreitada seria enorme para ser discutida apenas em um artigo de blog, vamos focar aqui no serviço de filmes, dentro da arquitetura abaixo.

Arquitetura de Micro serviços - Cinema
Arquitetura de Micro serviços – Cinema

Note que temos as responsabilidades já separadas neste desenho, dando um exemplo real de uma arquitetura usando micro serviços. Enquanto que em uma estrutura monolítica tradicional teríamos algo como um único webservice para o sistema de cinema inteiro (quem nunca fez um api.empresa.com na sua carreira?) ou no máximo dois, um para a bomboniére (Grocery Store) e outro para o sistema de ingressos em si (Booking).

Pensando em um dos casos de uso (ou histórias de usuário) mais comuns em um sistema de cinema temos o cliente que deseja ver os lançamentos no cinema mais próximo da sua casa. O diagrama abaixo ilustra um front-end mobile (app) consultando um serviço de cinemas que por sua vez consulta um serviço de filmes.

Consulta de Lançamentos do Cinema
Consulta de Lançamentos do Cinema

Por que dois serviços para entregar os lançamentos do cinema para o usuário?

Essa é a pergunta #1 de quem sempre construiu webservices monolíticos na sua vida.  A resposta é: segregação de responsabilidades (SRP, lembra?). O serviço de filmes (movies) tem apenas a preocupação de expor dados de filmes conforme consultado, sem qualquer regra de negócio ou julgamento quanto às chamadas. Já o serviço de catálogo do cinema (cinema catalog) é responsável pelas informações das salas de cinema existentes na rede e suas agendas.

Mas isso não é ineficiente, uma vez que temos de fazer sub-chamadas de serviços para atender a uma simples requisição do front-end?

Essa é a pergunta #2 de quem sempre buscou responder “desejos” do front-end em uma única chamada ao servidor. O engraçado é que eu recebo o mesmo tipo de indagação quando ensino programação orientada à objetos para quem está acostumado com procedural. Não são os milissegundos a mais que as sub-chamadas (seja entre serviços ou entre objetos) possuem que vão fazer a diferença na experiência de performance do sistema como um todo.

Como este artigo está ficando extenso, vou iniciar o desenvolvimento destes microservices na próxima parte desta série. Acesse a segunda parte aqui.

Curtiu o post? Então clica no banner abaixo e dá uma conferida no meu livro sobre programação web com Node.js!

O que achou desse artigo?
[Total: 6 Média: 5]

Publicado por

Luiz Duarte

Pós-graduado em computação, professor, empreendedor, blogueiro, autor, palestrante e programador.