Article image
Douglas Silva
Douglas Silva08/02/2022 23:03
Compartilhe

Microsserviços com Kafka + Micronaut + Java na prática!

  • #Maven
  • #Java
  • #Kafka

Eae turma?

Sou Desenvolvedor BackEnd no Banco Inter

Para quem quiser me adicionar

https://www.linkedin.com/in/douglas-silva-16614b14b/

Espero trazer um conteúdo bem bacana para quem já conhece Java e ainda não teve muito contato com Kafka e Micronaut.

A primeira pergunta é por que Micronaut e não Spring ?

Longe de mim julgar mas no momento eu estou mais familiarizado com o Micronaut e deixo aqui uma análise severa e detalhada, pro artigo não fugir muito do foco.

https://medium.com/@jvoliveiran/micronaut-x-spring-boot-uma-an%C3%A1lise-comparativa-de-desenvolvimento-desempenho-e-consumo-de-5b055169129b

Principalmente pra quem está iniciando o aprendizado vem sempre com o famoso CRUD! Faça um CRUD e você vai aprender tudo sobre APIs, rest, backend. Mas o que pouca gente sabe e que na verdade boa parte dos ambientes back ends em produção estão lotados de mensageria. Complementando, aqui vamos pôr a mão na massa e a teoria vemos depois. O que não me impede de compartilhar esse excelente artigo.

https://medium.com/assertqualityassurance/o-b%C3%A1sico-que-voc%C3%AA-precisa-saber-sobre-microservices-com-kafka-8cee23ce83d9

1 – Repositório – Você pode ir desenvolvendo os microsserviços no decorrer do artigo ou dar uma espiadinha aqui no meu repositório:

REPOSITORIO

O primeiro passo é criar seus dois microsserviços no micronaut launch que por sinal é um sistema bem semelhante ao spring initializer.

https://micronaut.io/launch/

image

Crie exatamente como está na imagem acima, o microsserviço de livro, adicionando as features de kafka, lombok e reactor. E depois com as mesmas configurações gere o mesmo projeto com o nome contador clicando em GENERATE PROJECT.

Vamos de: Micronaut 3.3, Java 11, Maven e Junit para testes aos quais não iremos adicionar.

Depois de baixado e descompactado joga numa pastinha, com o nome micronaut-kafka as duas pastas criadas que devem estar mais o menos assim.

image

Então temos nessa pasta dois microsserviços o de Livro:

Que tem em memória um pequeno cadastro de livros que você pode obter por método GET, listando todos, ou buscando por código qual livro deseja. Quando a busca por código é realizada, é enviada uma mensagem num tópico Kafka, registrando o objeto.

Já o microsserviço Contador:

Ele ouve a mensagem do Kafka registrando em memória cada vez que o microsserviço publica o objeto buscado. Assim ele conta por exemplo quantas vezes o livro 04 foi buscado.

Temos que ter em mente que os microsserviços NESSE CENÁRIO, só conversam por kafka e não por chamadas laterais.

Então vamos começar pelo microsserviço Livros. Abra sua IDE Java, e busque pela pasta livros que está dentro da pasta micronaut-kafka que eu tinha pedido para criar.

image

E já pode começar criando os packages dentro de com.livros as pastas: controller, model, producer e service assim como na imagem.

Dentro de model vamos começar criando a classe Livros, implementando ela da seguinte forma:

image

Vão surgir algumas anotations estranhas como essa @Introspected, assim deixo de lição de casa para entender para que serve cada uma.

A classe Livro é uma POJO que contém 3 atributos: String codigo, String nome e String autor.

O restante dos métodos da classe são construtores, getter, toString, hashcode e equals.

LINK COMPLETO DA CLASSE LIVROS

A próxima classe a ser implementada é a service chamada LivrosService.

image

Utilizamos classes services para tratar dos objetos antes de enviar para a próxima camada, assim como manda o padrão de arquitetura MVC, o qual sugiro dar uma boa estudada se ainda não domina bem o assunto.

Ao observar a LivrosService definimos uma lista de objetos Livros chamada livraria, e logo após o método com a anotation @PostConstruct instancia 4 objetos livros permanentes na memória, pois nesse microsservico não tratamos de persistência de dados como nos CRUDs.

Então temos o método listAll que retorna uma lista com todos os Livros, e um método Optional de Livros que busca o livro de acordo com o código.

Agora vamos para a controller.

image

Ao criar a classe LivrosController, definimos nessa camada os nomes dos endpoints que iremos tratar assim como manda a anotation @Controller.

Injetamos a LivrosService pois vamos precisar dela aqui e implementamos dois métodos GET, um que lista todos os livros salvos em memória, e o segundo método GET, que implementa no endpoint o código do livro e retorna o objeto de acordo com o código.

Até então não tratamos nada de mensageria nesse microsservico, mas vamos la!

Dentro na package producer vamos criar a Interface ContadorClient.

image

Essa interface dispõe de uma assinatura de método com uma anotation importantíssima a @Topic, a qual definimos o nome do tópico que iremos publicar a nossa mensagem, que no caso é o tópico "contador".

Em seguida também dentro de producer criamos a ContadorFiltro.

image

Essa classe é responsável por filtrar cada evento de busca de livro por ID e publicar no nosso tópico kafka, nota-se que foi injetada a Interface ContadorClient para utilizar o seu método assinado.

Beleza!

Peço para que ainda não rode seu microsservico pois ainda faltam algumas etapas até o final.

Agora vamos para o segundo microsservico o contador. Como no primeiro com o microsservico de livros ainda aberto mas minimizado. Abra-o com a sua ide e já crie os seguintes packages.

image

Consumer, controller, model e service.

OBS: para alterarmos a porta desse microsservico, temos que fazer uma leve alteracao na classe a Application de acordo com a imagem.

E vamos implementar o package model.

image

O model tem duas classes POJO, a Livros que é IDÊNTICA a do microsserviço Livros e a Classe Contador que dispõe de 2 parâmetros, String codigoLivro e Long contagem. Os métodos restantes são apenas construtores e getters.

Copiado a Livros e implementado a Contador vamos pra service.

image

No contador Service, definimos um Map contador, com chave livros e valores Long, além de dois métodos o atualizarContador, que incrementa de acordo com a quantidade de buscas de livros e o método listaContador, que lista pelo código, todos os livros buscados.

A Controller a ser implementada é mais simples e tem apenas um método GET.

image

Nota-se o nome do endpoint definido "contador" e a classe Service injetada para ser chamada assim que o método GET é chamado.

Falando de Kafka agora vamos implementar nosso escutador de mensagens dentro do package consumer. O ContadorConsumer.

image

Nessa classe temos um método void que recebe um objeto Livros, anotada com @Topic para definir qual o nome do tópico escutar utilizando o service injetado, para assim que ouvir uma mensagem o fluxo iniciar.

Para finalizar a implementação desse microsserviço vamos alterar a porta que ele deve se iniciar pois dois microsserviços rodando na 8080 certamente gerará um conflito.

Para isso copie o arquivo dentro da pasta resources e cole dentro da mesma pasta e adicione o prefixo -dev. Seus arquivos devem ficar assim.

image

Um chamado application.yml e o que você criou chamado application-dev.yml. Dentro desse arquivo apague tudo que tiver nele e cole isso: micronaut.server.port: 8081

Nos arquivos yml o espaçamento importa então deixe exatamente como na imagem:

image

Feito isso o seu microsserviço (contador) já estará configurado para rodar na porta 8081.

Concluído as configurações dos microsserviços agora é hora de configurar o Apache Kafka, e não vamos instala-lo no seu computador vamos utilizar o Docker!

Esse tutorial não e pra ensinar o uso do docker e virtualização, então vou passar um pouco longe dos fundamentos. Sendo assim depois que estiver o docker devidamente instalado na sua máquina, vamos utilizar um arquivo docker compose que disponibilizei no meu repositório.

Docker Compose Yml

Então você vai baixar ou executar o docker dentro da basta que se localiza esse docker-compose-yml. O docker compose a grosso modo é uma receita de bolo para o docker baixar imagens do que está descrito nele e criar containers configurados assim como o docker-compose manda. E para executar o docker-compose utilizamos o comando

docker-compose up -d

Também disponibilizei no meu repositório um arquivo chamado comands.txt com todos esses comandos que eu estarei utilizando.

image

Na pasta micronaut-kafka eu executei o comando docker-compose up -d, subirão alguns logs e se terminar dessa forma, significa que o docker baixou as imagens, criou os containers e executou todos eles que são 3 no total.

No docker desktop você vera os containers rodando dessa forma:

image

O kafka zookeeper é um complemento do kafka o qual não entrarei a fundo, o kafka_kafka é o container que iremos comunicar e o kafka_kafdrop é um serviço front end para o kafka, onde você consegue ver as mensagens e os tópicos registrados!

O docker mostra abaixo de cada container a porta do serviço rodando. Vamos experimentar primeiro o kafka_kafdrop, acessando o localhost:19000

image

Essa é a carinha do Kafdrop, nele observamos alguns status e a lista de tópicos registrados no kafka, abaixo vemos o tópico __consumer_offsets e o tópico contador. Se clicarmos no link dos tópicos poderemos ver as mensagens armazenadas.

image

No meu já dispõe de algumas mensagens devido aos testes que realizei antes de escrever o artigo. Note que as mensagens são objetos da classe Livros.

Agora vamos brincar com o kafka antes de colocar ele pra funcionar com nossos microsserviços.

Para isso abra um terminal da sua máquina e digite o seguinte código:

docker exec -it micronaut-kafka_kafka_1 /bin/bash

Note que depois do -it você coloca o nome do container que você quer se conectar, assim se a pasta que você colocou seu docker-compose for diferente o nome do container será diferente.

Esse comando pega o bash do linux rodando no container e traz para o seu terminal, assim você tem acesso aos comandos kafka diretamente no container.

image

Se o seu terminal assumir essa forma com cifrão $ significa que já está dentro do container.

O primeiro comando kafka que vamos utilizar é:

kafka-topics --create --topic topicoTese --bootstrap-server localhost:9092

Esse é o comando que cria tópicos e designamos o nome do nosso tópico de topicoTese.

OBS: Existem situações que de fato precisamos criar manualmente tópicos kafka, porem no caso desses microsserviços o próprio framework já se encarregou disso!

image

Então ele retorna mensagem de tópico criado! Sabendo disso se olharmos o Kafdrop novamente veremos lá o nosso tópico registrado.

image

Ala que bonitão !

Agora que temos o tópico vamos de fato entender o princípio da mensageria, onde temos um escutador (subscribe), e um publicador (publisher), e para essa brincadeira vamos precisar de dois terminais do container kafka ok? Abram dois terminais e entrem dentro do container nos dois terminais como eu ensinei ali em cima.

image

Dessa forma. Precisamos de dois terminais porque vamos deixar um para publicar a mensagem e o outro para escutar, e tendo os dois, nós acompanhamos isso em tempo real!

Lembrando que! Os comandos kafka só funcionarão se você estiver dentro do container OK.

Dentro de um você digita:

kafka-console-consumer --topic topicoTese --from-beginning --bootstrap-server localhost:9092

Esse é o consumer (escutador, subscribe), que ficara sempre ouvindo a mensagem no tópico "topicoTese"

Já no outro terminal você digita:

kafka-console-producer --topic topicoTese --bootstrap-server localhost:9092

Nesse você escrevera manualmente as mensagens, ele e o producer, (publicador, publisher).

image

Note que o consumer, o bash simplesmente sumiu como se tivesse travado, mas isso é normal pois agora ele está escutando o tópico "topicoTese", e o producer surgiu um ">" onde você deve imputar a primeira mensagem, vamos lá!

image

Primeiramente eu escrevi melancia e enviei, laranja e enviei, limonada e enviei, e depois uma frase e enviei. Nota-se que a mensagem chega quase instantaneamente no consumer, e se você também conseguiu publicar essas mensagens e receber é sinal que o seu kafka está precisamente configurado!

OBS: Se formos explorar o Kafdrop, todas as mensagens estarão lá.

image

Bora lá então voltar nos nossos microsserviços?

Eu queria muito falar que temos que configurar algumas coisas do kafka, mas como importamos a feature do kafka quando criamos o projeto, ele já vem configurado na porta padrão do kafka a 9092. Isso você pode observar no arquivo application.yml dentro da pasta resources dos dois microsserviços.

image

Agora é só correr pro abraço e estartar os dois microsserviços.

image

Nota-se que o microsserviço de Livros não gera quase nada de logs, já o contador ...

Com os dois serviços rodando vamos testar primeiro o contador fazendo um GET no seu endpoint, diretamente no navegador. Você lembra qual era o endpoint ? É esse aqui:

localhost:8081/contador

image

Quando damos um GET no endpoint do contador ele me retorna uma lista vazia, pois até então ele não consumiu nenhuma mensagem do kafka para contar e armazenar em memória.

Agora vamos dar um GET no endpoitn do Livros

localhost:8080/livros

image

E exatamente como programamos ele retorna uma lista com todos os livros cadastrado via código. OBS: Estou utilizando uma extensão do chrome que organiza objetos json, se você não tiver, o json ficara inteiro em uma linha, que também é uma resposta correta.

Nota-se que até então não houve comunicação entre os microsserviços, pois definimos em ambos os códigos que apenas aconteceria se houvesse uma busca por código do livro.

Vamos nessa então?

Para definir uma busca por código damos um GET com o código no final do endpoint

Ex: localhost:8080/livros/02

image

Voa-la! Após o GET em Livros e em seguida um GET em Contador, ele já começou a contabilizar, e tivemos com êxito a nossa comunicação entre microsserviços!

Se você chegou aqui com esse resultado, MEUS PARABÉNS!

E então podemos brincar mais, buscando cada um dos 4 livros várias vezes.

E você acompanhar de perto os logs do Contador, para cada mensagem ouvida, e também pode ver no Kafdrop todas as mensagens publicadas.

image

Parece muito trabalho pra um pequeno resultado, mas se for pensar em todas as tecnologias aplicadas aqui, tenho certeza que valeu a pena!

Existem algumas perguntas respondidas:

1 - Você utilizou Lombok mas não utilizou direito, sim! .. apenas sim! deu vontade de escrever alguns métodos tradicionais na mão novamente.

2 - Cadê a serialização ????? Isso é um assunto que anda sempre junto com a mensageria, mas talvez informação demais pra esse artigo. Deixei, um link bem bacana no arquivo comands.txt pra você conhecer mais sobre.

3 - Existem alternativas ao kafka ??? SIM! Mas o kafka ainda é muuuito utilizado mundialmente, e ainda está no hype.

Para mais perguntas deixo aberto aqui para debatermos o assunto.

Baseei o artigo na própria documentação do Micronaut:

https://guides.micronaut.io/latest/micronaut-kafka-gradle-java.html

Valeu Turma!

Compartilhe
Comentários (0)