Skip to content

ec-ayrton/LabNFeChallenger

Repository files navigation

🚀 Sobre o Desafio (The Challenge)

O LabNFeChallenger é um laboratório de engenharia de software projetado para simular o processamento de Notas Fiscais Eletrônicas (NF-e) sob condições extremas de estresse de carga e restrição severa de recursos de infraestrutura.

O principal objetivo deste projeto é receber milhares de requisições contendo payloads XML de NF-e, garantir a resiliência dos dados e processá-los de forma assíncrona, simulando uma comunicação real com a SEFAZ que impõe uma latência síncrona obrigatória de 30 segundos por nota.

🛑 As Restrições do Ambiente:

  • Memória Extremamente Limitada: A aplicação Java é forçada a rodar com um limite máximo de 128MB de Heap (-Xmx128m), impossibilitando o empilhamento de requisições pesadas diretamente na memória síncrona do servidor HTTP.
  • Gargalo Externo de Tempo: Cada nota precisa obrigatoriamente aguardar uma simulação de rede de 30 segundos (Thread.sleep(30000)) para espelhar o comportamento do WebService do governo.

🗺️ Evolução da Arquitetura: O Antes vs. O Agora

Para sobreviver a esse cenário sem estourar a memória do servidor (OutOfMemoryError) e sem travar as requisições dos clientes HTTP, o design do sistema evoluiu drasticamente:

❌ Como Era Antes (Abordagem Tradicional)

No modelo inicial, as requisições HTTP batiam no Controller e tentavam resolver o processamento de forma acoplada ou utilizando mensageria desalinhada com a infraestrutura:

  • Bloqueio de Threads HTTP: O servidor Tomcat tentava gerenciar milhares de conexões abertas simultaneamente, esperando a resposta de 30 segundos da SEFAZ. As threads do Tomcat esgotavam rapidamente.

⚡ Como É Agora (Arquitetura Orientada a Eventos de Alta Performance)

A arquitetura atual foi completamente remodelada para separar a camada de Ingestão (síncrona/rápida) da camada de Processamento (assíncrona/paralela):

  • Desacoplamento Total: O Controller HTTP apenas valida a presença do payload, gera um identificador único (Protocolo UUID) e despacha a mensagem imediatamente para o Apache Kafka. O ciclo de vida do request HTTP dura milissegundos, liberando a thread do Tomcat na hora.
  • Paralelismo Real Baseado em Partições: O ecossistema agora gerencia o ciclo de vida do tópico de forma programática através do Spring, forçando o provisionamento de 5 partições balanceadas.
  • Consumo Concorrente Escalonado: O Worker de processamento utiliza a propriedade de concorrência ativa (concurrency = 5), acionando 5 threads independentes e dedicadas em background. Cada thread assume o controle de uma partição do Kafka, permitindo que 5 notas fiscais sejam transmitidas à SEFAZ simultaneamente, multiplicando a vazão do sistema por 5 sem elevar o consumo de memória RAM da aplicação.

❌ Como Era Antes (Abordagem Tradicional)

No modelo inicial, as requisições HTTP batiam no Controller e tentavam resolver o processamento de forma acoplada:

Diagrama da Arquitetura Síncrona com Gargalo

  • Bloqueio de Threads HTTP: O servidor Tomcat tentava gerenciar milhares de conexões abertas simultaneamente...
  • Memória: Conforme requisições chegavam eram enfileiradas em memória o que levava ao estouro...

⚡ Como É Agora (Arquitetura Orientada a Eventos de Alta Performance)

A arquitetura atual foi completamente remodelada para separar a camada de Ingestão da camada de Processamento:

Diagrama da Arquitetura Reativa com Apache Kafka

  • Desacoplamento Total: O Controller HTTP apenas valida a presença do payload e gera um UUID...
  • Paralelismo Real Baseado em Partições: O ecossistema agora gerencia o ciclo de vida do tópico com 5 partições...
  • Memória: As requisições agoram ficam armazenadas no Kafka, o que diminue pressão da memória e gera agilidade no processamento.

🏗️ Tecnologias Utilizadas & Configurações de Performance (O "Pulo do Gato")

Para que a arquitetura orientada a eventos consiga operar de forma estável dentro do limite severo de 128MB de RAM, cada componente do ecossistema foi calibrado milimetricamente. Abaixo estão as tecnologias que compõem o laboratório e as otimizações aplicadas.

🛠️ Stack Tecnológica

  • Java 21: Utilização da versão LTS mais recente para máxima eficiência de gerenciamento de memória da JVM.
  • Spring Boot 3.4.2: Framework base para o desenvolvimento dos microsserviços (Controller, Ingestão e Mensageria).
  • Apache Kafka 4.2.1: Configurado em modo KRaft (Single Node), eliminando a complexidade e o overhead de memória do antigo ZooKeeper.
  • AKHQ: Interface web administrativa leve para monitoramento de tópicos, partições e comportamento do Lag dos grupos de consumo.
  • K6 (Grafana): Ferramenta de teste de carga baseada em scripts JavaScript para injeção massiva de requisições HTTP simulando o ambiente de produção.

⚡ Engenharia e Ajustes de Performance

O segredo da estabilidade deste laboratório está no arquivo application.properties. As configurações foram divididas estrategicamente em três pilares:

1. Controle de Vazão do Servidor Web (Tomcat)

Por padrão, o Spring Boot abre até 200 threads para processar requisições HTTP simultâneas. Em um ambiente com pouca RAM, isso causa estouro de memória imediato devido ao peso de cada stack de thread.

# Reduz o consumo de RAM limitando as threads simultâneas ativas no Tomcat
server.tomcat.threads.max=20

# Mantém a resiliência do teste segurando o excedente do K6 na fila do S.O.
server.tomcat.accept-count=200

O impacto: O Tomcat processa até 20 requisições por vez. O restante fica aguardando em uma fila de rede segura gerenciada pelo Sistema Operacional, evitando que a JVM crie threads em excesso e sofra um OutOfMemoryError.

2. Ingestão Instantânea (Produtor Kafka)

O produtor precisa esvaziar o buffer do Controller o mais rápido possível para liberar as conexões HTTP dos clientes.

# Força o envio IMEDIATO do payload para o broker sem reter pacotes em memória (0ms)
spring.kafka.producer.linger.ms=0

# Exige confirmação apenas do nó líder, minimizando o tempo de espera do request síncrono
spring.kafka.producer.acks=1

# Impede que o Controller fique travado indefinidamente se o cluster Kafka oscilar
spring.kafka.producer.properties.max.block.ms=5000

3. Proteção do Consumidor e Estabilidade do Cluster (Worker)

Como o processamento da SEFAZ introduz uma latência artificial de 30 segundos, o consumidor corre o risco de ser expulso pelo Kafka se passar tempo demais preso em um lote grande de mensagens.

# Puxa no máximo 10 mensagens por lote (Evita sufocar o Heap com Strings de XML pesadas)
spring.kafka.consumer.max-poll-records=10

# Eleva o limite de tempo para 10 minutos para que o Java processe o lote sem sofrer timeout
spring.kafka.consumer.properties.max.poll.interval.ms=600000

Impacto: O Kafka entende que o Worker está vivo e trabalhando de forma saudável, mesmo processando as mensagens lentamente devido ao gargalo externo do governo, eliminando o fantasma do estado de Rebalancing infinito.

🏃 Como Executar o Laboratório (Passo a Passo)

Siga este roteiro cronológico para subir a infraestrutura limpa, ativar a automação do Spring Boot e disparar os testes de carga com o K6.

📋 Pré-requisitos

Antes de começar, certifique-se de ter instalado em sua máquina Linux:

  • Docker e Docker Compose
  • Java 21 JDK
  • K6 (Ferramenta de testes de carga da Grafana)

🚀 Passo 1: O Rolo Compressor do Docker (Limpeza Total)

Para garantir que nenhuma configuração corrompida ou volume fantasma interfira no seu teste, execute a limpeza absoluta do ambiente no terminal:

docker compose down -v --remove-orphans && docker system prune -f

🚀 Passo 2: Subir a Infraestrutura do Cluster

Com o ambiente zerado, inicie os containers do Apache Kafka (KRaft) e da interface visual do AKHQ em background:

docker compose up -d

🚀 Passo 3: Iniciar a Aplicação Spring Boot

Abra o projeto na sua IDE (IntelliJ/Eclipse) ou utilize o terminal para iniciar o Java.

Assim que a aplicação der o Start completo (Started LabNFeChallengerApplication), a classe de configuração programática KafkaConfig entrará em ação automaticamente, criando o tópico nfe-recebidas com as 5 partições perfeitamente calibradas antes do recebimento de qualquer requisição.

Passo 4: Disparar o Teste de Carga com o K6

Abra uma nova janela no seu terminal e execute o script do K6 para injetar uma carga controlada de usuários simulando o envio simultâneo de XMLs de Notas Fiscais contra o endpoint da Controller:

k6 run nfe-carga.js

O comando acima vai manter varios usuários virtuais batendo na API síncrona sem parar pelo período de x segundos determinados no arquivo nfe-carga.js .

📊 Como Monitorar e Validar os Resultados

Para validar se o paralelismo e o comportamento das threads estão funcionando conforme o esperado, você dispõe de duas ferramentas de monitoramento:

1. Linha de Comando (Terminal)

Você pode interrogar diretamente o coração do Kafka para extrair os metadados brutos do seu grupo de consumo. Execute o comando abaixo no terminal:

docker run --net=host --rm confluentinc/cp-kafka:7.6.0 kafka-consumer-groups --bootstrap-server 127.0.0.1:9094 --describe --group nfe-group

Ao executar este comando consecutivamente com um intervalo de alguns segundos, você poderá observar:

  • A coluna CURRENT-OFFSET de todas as partições subindo de forma simultânea.

  • A coluna LAG diminuindo de forma constante, provando que as mensagens estão sendo limpas da fila de maneira distribuída.

🖥️ 2. Interface Visual (AKHQ Panel)

Acesse no seu navegador a URL administrativa do painel do AKHQ:

Endereço: http://127.0.0.1:8089

Nesta tela, navegue até o menu de tópicos e observe os dois indicadores principais para validar a matemática do ecossistema:

  • Count: Representa o volume total de payloads que o K6 conseguiu registrar com sucesso no disco do Kafka (o histórico acumulado estático que não diminui).

  • nfe-group Lag (Caixinha Verde): Exibe o saldo exato de notas que ainda aguardam processamento. Ao atualizar a página (F5), você verá esse indicador derreter em blocos de 5 em 5 mensagens por segundo, confirmando a saúde e a alta performance do paralelismo das suas 5 threads de consumo em background.

About

"Laboratório de mensageria e processamento assíncrono de Notas Fiscais Eletrônicas (NF-e). Arquitetura resiliente para recepção, validação de regras fiscais brasileiras, assinatura digital e simulação de integração com a SEFAZ."

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages