JavaRush /Blogue Java /Random-PT /Um guia para microsserviços Java. Parte 1: Noções básicas...

Um guia para microsserviços Java. Parte 1: Noções básicas e arquitetura de microsserviços

Publicado no grupo Random-PT
Neste guia, você aprenderá o que são microsserviços Java, como projetá-los e criá-los. Também aborda questões sobre bibliotecas de microsserviços Java e a viabilidade do uso de microsserviços. Tradução e adaptação de microsserviços Java: um guia prático .

Microsserviços Java: Noções básicas

Para entender os microsserviços, primeiro você deve definir o que eles não são. Não é um “monólito” - monólito Java: o que é e quais são as suas vantagens ou desvantagens? Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 1

O que é um monólito Java?

Imagine que você trabalha para um banco ou uma startup de fintech. Você fornece aos usuários um aplicativo móvel que eles podem usar para abrir uma nova conta bancária. No código Java, isso resultará na presença de uma classe controladora. Simplificado, fica assim:
@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
Você precisa do controlador para:
  1. Confirmado o formulário de inscrição.
  2. Verificou os riscos do endereço do usuário para decidir se lhe forneceria uma conta bancária.
  3. Abriu uma conta bancária.
A classe BankControllerserá empacotada junto com o restante de suas fontes em um arquivo bank.jar ou bank.war para implantação - este é um bom e velho monólito contendo todo o código necessário para administrar seu banco. Como estimativa aproximada, o tamanho inicial de um arquivo .jar (ou .war) variará de 1 a 100 MB. Agora você pode simplesmente executar o arquivo .jar em seu servidor... e isso é tudo que você precisa fazer para implantar seu aplicativo Java. Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 2Imagem, retângulo superior esquerdo: implantação de um banco mono(lítico) java -jar bank.jar (cp .war/.ear em appserver). Retângulo direito: navegador aberto.

Qual é o problema com os monólitos Java?

Não há nada inerentemente errado com os monólitos Java. No entanto, a experiência mostra que se no seu projeto:
  • Existem muitos programadores/equipes/consultores trabalhando...
  • ...sobre o mesmo monólito sob pressão de clientes com requisitos muito vagos...
  • dentro de alguns anos...
... então, neste caso, seu pequeno arquivo bank.jar se transforma em um imenso gigabyte de código sozinho, o que é assustador até mesmo de abordar, quanto mais de implantar.

Como reduzir o tamanho de um monólito Java?

Surge uma pergunta natural: como diminuir o monólito? No momento, seu bank.jar está sendo executado em uma JVM, um processo em um servidor. Nem mais nem menos. E neste momento um pensamento lógico pode vir à mente: “Mas o serviço de verificação de risco pode ser utilizado por outros departamentos da minha empresa! Não está diretamente relacionado ao meu aplicativo bancário monolítico! Talvez devesse ser cortado do monólito e implantado como um produto separado? Isto é, tecnicamente falando, executá-lo como um processo Java separado.”

O que é um microsserviço Java?

Na prática, esta frase significa que agora a chamada do método riskCheck()não será feita a partir do BankController: este método ou componente bean com todas as suas classes auxiliares será movido para seu próprio projeto Maven ou Gradle. Ele também será implantado e colocado sob controle de versão independentemente do monólito bancário. No entanto, todo esse processo de extração não transforma seu novo módulo RiskCheck em um microsserviço em si, uma vez que a definição de microsserviço está aberta à interpretação. Isso leva a discussões frequentes dentro de equipes e empresas.
  • São 5 a 7 aulas em um projeto micro ou o quê?
  • 100 ou 1000 aulas... ainda micro?
  • O microsserviço geralmente está relacionado ao número de classes ou não?
Vamos deixar o raciocínio teórico para trás e, em vez disso, nos ater a considerações pragmáticas e fazer o seguinte:
  1. Vamos chamar todos os serviços implantados separadamente de microsserviços, independentemente de seu tamanho ou limites de domínio.
  2. Vamos pensar em como organizar a comunicação entre serviços. Nossos microsserviços precisam de maneiras de se comunicarem entre si.
Então, para resumir: anteriormente você tinha um processo JVM, um monólito sólido para administrar o banco. Agora você tem um processo JVM monolítico bancário e um microsserviço RiskCheck separado que é executado em seu próprio processo JVM. E agora, para verificar riscos, seu monólito deve chamar esse microsserviço. Como fazer isso?

Como estabelecer comunicação entre microsserviços Java?

Em geral e em geral, existem duas opções - comunicação síncrona e assíncrona.

Comunicação síncrona: (HTTP)/REST

Normalmente, a comunicação sincronizada entre microsserviços ocorre por meio de serviços HTTP e REST que retornam XML ou JSON. Claro, pode haver outras opções - pegue pelo menos Google Protocol Buffers . Se precisar de uma resposta imediata, é melhor usar a comunicação REST. No nosso exemplo, é exatamente isso que precisa ser feito, uma vez que é necessária uma verificação de risco antes de abrir uma conta. Se não houver verificação de risco, não há conta. Discutiremos as ferramentas abaixo, na seção “ Quais bibliotecas são melhores para chamadas Java REST síncronas ”.

Mensagens - Comunicação Assíncrona

A comunicação assíncrona de microsserviços normalmente é realizada pela troca de mensagens com uma implementação JMS e/ou usando um protocolo como AMQP . Escrevemos “normalmente” aqui por um motivo: digamos que o número de integrações de e-mail/SMTP não pode ser subestimado. Use-o quando não precisar de uma resposta imediata. Por exemplo, o usuário clica no botão “comprar agora” e você, por sua vez, deseja gerar uma fatura. Este processo certamente não deve ocorrer dentro do ciclo de solicitação-resposta de compra do usuário. Abaixo descreveremos quais ferramentas são melhores para mensagens Java assíncronas .

Exemplo: chamada de API REST em Java

Digamos que escolhemos a comunicação síncrona de microsserviços. Neste caso, nosso código Java (aquele que apresentamos acima) em baixo nível ficará mais ou menos assim. (por baixo nível aqui queremos dizer o fato de que, para comunicação de microsserviços, geralmente são criadas bibliotecas de clientes que abstraem você das chamadas HTTP reais).
@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
Com base no código, fica claro que agora precisamos implantar dois (micro) serviços Java, Bank e RiskCheck. Como resultado, teremos dois processos JVM em execução. Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 3Isso é tudo que você precisa para desenvolver um projeto de microsserviços Java: basta construir e implantar pedaços menores (arquivos .jar ou .war) em vez de um monolítico. A resposta à pergunta permanece obscura: como deveríamos dividir o monólito em microsserviços? Quão pequenas devem ser essas peças, como determinar o tamanho correto? Vamos checar.

Arquitetura de microsserviços Java

Na prática, as empresas desenvolvem projetos de microsserviços de diferentes maneiras. A abordagem depende se você está tentando transformar um monólito existente em um projeto de microsserviços ou iniciando o projeto do zero.

Do monólito aos microsserviços

Uma das ideias mais lógicas é extrair microsserviços de um monólito existente. Observe que o prefixo “micro” aqui não significa realmente que os serviços extraídos serão realmente pequenos; este não é necessariamente o caso. Vejamos a base teórica.

Ideia: dividir o monólito em microsserviços

Uma abordagem de microsserviço pode ser aplicada a projetos legados. E é por causa disso:
  1. Na maioria das vezes, esses projetos são difíceis de manter/alterar/expandir.
  2. Todos, desde os desenvolvedores até a administração, desejam simplificação.
  3. Você tem limites de domínio (relativamente) claros, o que significa que sabe exatamente o que seu software deve fazer.
Voltando ao nosso exemplo, isso significa que você pode olhar para o seu monólito bancário Java e tentar dividi-lo através dos limites do domínio.
  • Portanto, seria razoável separar o processamento de dados do usuário (como nomes, endereços, números de telefone) em um microsserviço separado “Gerenciamento de contas”.
  • Ou o já citado “Módulo Verificador de Riscos” que verifica os níveis de risco do usuário e pode ser utilizado por diversos outros projetos ou mesmo departamentos da empresa.
  • Ou um módulo de faturação que envia faturas em formato PDF ou por correio.

Implementação de uma ideia: deixe outra pessoa fazer isso

A abordagem descrita acima fica ótima em papel e em diagramas do tipo UML. Porém, nem tudo é tão simples. A sua implementação prática requer uma preparação técnica séria: a lacuna entre a nossa compreensão do que seria bom extrair de um monólito e o próprio processo de extração é enorme. A maioria dos projetos empresariais chega a um estágio em que os desenvolvedores têm medo de, por exemplo, atualizar uma versão do Hibernate com 7 anos de idade para uma mais recente. As bibliotecas serão atualizadas junto com ele, mas existe o perigo real de quebrar alguma coisa. Então, esses mesmos desenvolvedores agora precisam vasculhar códigos legados antigos com limites de transação de banco de dados pouco claros e extrair microsserviços bem definidos? Na maioria das vezes, este problema é muito complexo e não pode ser “resolvido” num quadro branco ou em reuniões de arquitetura. Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 4Para citar o desenvolvedor do Twitter @simonbrown: Direi isso repetidamente... se as pessoas não conseguirem construir monólitos corretamente, os microsserviços não ajudarão. Simão Brown

Projeto do zero baseado em arquitetura de microsserviços

Para novos projetos Java, os três itens numerados da parte anterior parecem um pouco diferentes:
  1. Você começa do zero, então não há “bagagem” para manter.
  2. Os desenvolvedores gostariam de manter as coisas simples no futuro.
  3. Problema: você tem uma imagem muito mais confusa dos limites do domínio: você não sabe o que seu software realmente deve fazer (dica: ágil;))
Isso está levando as empresas a experimentar novos projetos com microsserviços Java.

Arquitetura técnica de microsserviços

O primeiro ponto parece ser o mais óbvio para os desenvolvedores, mas também há quem o desencoraje fortemente. Hadi Hariri recomenda a refatoração "Extract Microservice" no IntelliJ. E embora o exemplo a seguir seja bastante simplificado, as implementações observadas em projetos reais, infelizmente, não vão muito longe disso. Antes dos microsserviços
@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
Com microsserviço Java de substring
@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
Então você está essencialmente agrupando uma chamada de método Java em uma chamada HTTP, sem nenhuma razão óbvia para fazer isso. Um dos motivos, porém, é este: falta de experiência e tentativa de forçar uma abordagem de microsserviços Java. Recomendação: Não faça isso.

Arquitetura de microsserviços orientada a fluxo de trabalho

A próxima abordagem comum é dividir os microsserviços Java em módulos baseados em fluxo de trabalho. Exemplo da vida real: na Alemanha, quando você vai a um médico (público), ele deve registrar sua visita em seu sistema médico de CRM. Para receber o pagamento do seguro, ele enviará dados sobre o seu tratamento (e o tratamento de outros pacientes) ao intermediário via XML. O corretor examinará este arquivo XML e (simplificado):
  1. Irá verificar se o arquivo XML correto foi recebido.
  2. Ele verificará a plausibilidade dos procedimentos: digamos, uma criança de um ano que recebeu três procedimentos de limpeza dos dentes em um dia de um ginecologista parece um tanto suspeita.
  3. Combinará XML com alguns outros dados burocráticos.
  4. Encaminhará o arquivo XML para a seguradora para iniciar os pagamentos.
  5. E enviará o resultado ao médico, passando-lhe a mensagem “sucesso” ou “reenvie esta gravação assim que fizer sentido”.
Observação. Neste exemplo, a comunicação entre microsserviços não desempenha um papel, mas poderia muito bem ser feita de forma assíncrona por um intermediário de mensagens (por exemplo, RabbitMQ), uma vez que o médico não recebe feedback imediato de qualquer maneira. Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 5Novamente, isso parece ótimo no papel, mas surgem questões naturais:
  • É necessário implantar seis aplicativos para processar um arquivo XML?
  • Esses microsserviços são verdadeiramente independentes uns dos outros? Eles podem ser implantados independentemente um do outro? Com diferentes versões e esquemas de API?
  • O que o microsserviço de credibilidade faz se o microsserviço de verificação não funcionar? O sistema ainda está funcionando?
  • Esses microsserviços compartilham o mesmo banco de dados (certamente precisam de alguns dados comuns nas tabelas do banco de dados) ou cada um deles possui os seus próprios?
  • … e muito mais.
Curiosamente, o diagrama acima parece mais simples porque cada serviço agora tem sua finalidade precisa e bem definida. Costumava se parecer com este monólito assustador: Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 6embora você possa argumentar sobre a simplicidade desses diagramas, agora você definitivamente precisa resolver esses desafios operacionais adicionais.
  • Você não precisa implantar apenas um aplicativo, mas pelo menos seis.
  • Você pode até precisar implantar vários bancos de dados, dependendo de até onde deseja ir na arquitetura de microsserviços.
  • Você precisa ter certeza de que cada sistema está online e funcionando corretamente.
  • Você precisa ter certeza de que suas chamadas entre microsserviços são realmente resilientes (consulte Como tornar um microsserviço Java resiliente?).
  • E tudo o mais que esta configuração implica - desde configurações de desenvolvimento local até testes de integração.
Então a recomendação seria:
  • Se você não é Netflix (provavelmente você não é Netflix)...
  • A menos que você tenha habilidades de trabalho super fortes onde você abre o ambiente de desenvolvimento e ele chama um macaco do caos que joga fora seu banco de dados de produção que é facilmente restaurado em 5 segundos.
  • ou você se sente como @monzo e está disposto a experimentar 1.500 microsserviços só porque pode.
→ Não faça isso. E agora é menos hiperbólico. Tentar modelar microsserviços através dos limites do domínio parece bastante razoável. Mas isso não significa que você precisa pegar um fluxo de trabalho e dividi-lo em pequenas partes individuais (receber XML, validar XML, encaminhar XML). Portanto, sempre que você iniciar um novo projeto com microsserviços Java e os limites do domínio ainda forem muito vagos, tente manter o tamanho dos seus microsserviços em um nível baixo. Você sempre pode adicionar mais módulos posteriormente. E certifique-se de ter DevOps avançado na equipe/empresa/divisão para dar suporte à sua nova infraestrutura.

Arquitetura poliglota ou de microsserviços orientada para equipes

Existe uma terceira abordagem, quase libertária, para o desenvolvimento de microsserviços: permitir que equipes ou mesmo indivíduos implementem histórias de usuários usando qualquer número de linguagens ou microsserviços (os profissionais de marketing chamam essa abordagem de “programação poliglota”). Assim, o serviço de validação XML descrito acima poderia ser escrito em Java, enquanto o microsserviço de validação ao mesmo tempo poderia ser escrito em Haskell (para torná-lo matematicamente correto). Para o microsserviço de encaminhamento de seguro, você pode usar Erlang (porque ele realmente precisa ser escalonado;)). O que pode parecer divertido do ponto de vista de um desenvolvedor (desenvolver o sistema perfeito com sua linguagem perfeita em um ambiente isolado) na verdade nunca é o que a organização deseja: homogeneização e padronização. Isso significa um conjunto relativamente padronizado de linguagens, bibliotecas e ferramentas para que outros desenvolvedores possam continuar a oferecer suporte ao seu microsserviço Haskell no futuro, quando você avançar para pastagens mais verdes. Um guia para microsserviços Java.  Parte 1: Noções básicas e arquitetura de microsserviços - 8A história mostra que a padronização geralmente se torna profundamente enraizada. Por exemplo, os desenvolvedores de grandes empresas da Fortune 500 às vezes nem sequer tinham permissão para usar o Spring porque “não fazia parte do roteiro tecnológico da empresa”. Contudo, uma transição completa para a abordagem poliglota é quase a mesma coisa, o outro lado da mesma moeda. Recomendação: Se você for usar programação poliglota, tente menos variedade dentro do mesmo ecossistema de linguagem de programação. Portanto, é melhor usar Kotlin e Java juntos (ambas as linguagens são baseadas na JVM e são 100% compatíveis entre si), em vez de Java e, digamos, Haskell. Na próxima parte, você aprenderá como implantar e testar microsserviços Java.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION