Padrões de Microserviços — Service discovery — Eureka
Quando se constrói uma aplicação monolítica, é comum termos divisões dentro da sua estrutura para separar as funcionalidades, em alguns casos chamamos estas divisões de módulos.
Uma vez que os diversos módulos estão na mesma aplicação, é comum um módulo se comunicar com outro, de maneira a lidar com a complexidade de negócio, deixando o front-end apenas o trabalho exibir os dados.
A medida que começamos a quebrar esta aplicação, em aplicações menores, alguns códigos que antes eram feitos no back-end, começam a aparecer no front-end, normalmente este tipo de código aparece como uma cadeia de chamadas em cascata para diversos serviços, de maneira que o front-end faça o papel de cola entre os módulos que antes estavam todos juntos.
Enquanto seus serviços estão sendo executados apenas em uma máquina, a comunicação parece relativamente tranquila, pois basta enviar a requisição pro IP e porta desejada.
Enquanto a solução permanecer como no diagrama acima, é relativamente aceitável deixar que o cliente lide com a complexidade de chamar os serviços que ele deseja, e decida oque fazer com a resposta de cada requisição.
Porém, a medida que o negócio cresce e a maturidade das equipes de desenvolvimento de software também cresce, eles veem que está cada vez mais difícil de manter a aplicação cliente que precisa:
- Saber onde está cada serviço, e quando é necessário mudar o IP ou porta o cliente precisa ser ajustado;
- Cada serviço precisa estar exposto, oque aumenta a superfície de ataques;
- Lidar com latência de rede, talvez precise ser implementado no front;
- Realizar estrangulamento de dados, para não afogar o banco de dados talvez precise ser implementado no front;
- Dificulta o rastreamento dos dados;
- Uma simples operação pode acabar por realizar muitas chamadas aos serviços, resultando em lentidão. Se esta complexidade se mante-se no servidor, um “agregador” poderia realizar diversas chamadas todas na rede interna, tornando tudo mais eficiente;
- Cliente precisa fazer muitas requisições, quando se trata de um dispositivo móvel, isto implica em maior consumo de dados móveis e e bateria;
- Regras de negócio, que são inerentes ao modelo de micro-serviços precisam estar implementadas no cliente como por exemplo o “chained ou aggregator microservice design pattern”
Vamos escalar horizontalmente?
Em algum momento você vai precisar escalar suas aplicações horizontalmente. Que é basicamente, colocar uma cópia da sua aplicação rodando em outra máquina. Como se já não fosse difícil o bastante, agora cada serviço tem vários IPs e de forma dinâmica pois aumentamos e diminuímos o número de máquinas de forma automática (auto scaling).
Além de todos as dificuldades já listadas, temos de lidar com a complexidade de uma arquitetura distribuída e auto escalável no front, não vai demorar muito até todos perceberem que não é sustentável, que o nível de stress das equipes de front-end vai subir e muito.
Service discovery vem ao resgate
A solução é devolver a complexidade que foi levado pro front, de volta ao seu dono, o back-end, com oque hoje conhecemos como Service discovery ? Se você é programador, talvez veja semelhança com o padrão de projeto Observer.
Com o Service Discovery, o cliente não vai mais enviar suas requisições a cada serviço, ele irá enviar para um local único (Shopping), que através do Service Siscovery saberá para onde encaminhar, então receber de volta a requisição e devolve-la pro cliente.
Para isto funcionar, cada serviço precisa registrar-se no Service Discovery, e quando for necessário, quem precisar enviar uma requisição perguntará para o Service Discovery qual o serviço está em execução.
Neste ultimo desenho, temos um modelo mais escalável e resiliente a falhas, porém introduzimos mais:
- Complexidade arquitetural;
- Complexidade de localizar erros;
- Necessidade de monitoramento;
- Necessidade de rastrear a requisição;
- Ponto único de falha (Shopping)
- Necessidade de CD (Continuous delivery)