Tecnologia
Project Loom e Spring Boot: um estudo de caso de performance
3 minutos de leitura
Para desenvolvedores Java, o modelo “thread-per-request” sempre foi sinônimo de código simples e legível. No entanto, em um mundo de microsserviços e alta concorrência, esse modelo atinge um gargalo: as threads de plataforma, gerenciadas pelo sistema operacional, são um recurso caro e limitado. Quando uma thread bloqueia em uma operação de I/O (como uma chamada a um banco de dados ou a uma API externa), ela fica ociosa, desperdiçando recursos e limitando a capacidade do sistema de lidar com novas requisições.
Por anos, a solução para isso foi a complexidade da programação reativa. Com o Java 21 e o Project Loom, a promessa é obter a escalabilidade do reativo com a simplicidade do código síncrono através das Virtual Threads.
Mas qual o impacto real dessa mudança? Para responder a essa pergunta, conduzi um estudo de performance A/B em uma API REST para medir, com dados concretos, o ganho de performance ao habilitar as Virtual Threads.
O Laboratório: criando um ambiente de teste controlado
Para garantir que os resultados fossem confiáveis e reprodutíveis, o primeiro passo foi criar um ambiente de teste isolado. A aplicação sob teste é uma API REST para transações financeiras, construída com Spring Boot 3.5.5 e Java 21.
O ambiente de teste foi 100% conteinerizado e com recursos controlados, composto por:
- Aplicação Sob Teste: Rodando em um contêiner Docker com limites de 1.5 vCPUs e 2GB de RAM.
- Dependência Externa Mockada: A API externa do Tesouro foi simulada com o WireMock, rodando em um contêiner separado com 0.5 vCPU e 1GB de RAM. O mock foi configurado com um delay de resposta variável (distribuição log-normal) para simular a latência de uma rede real.
- Gerador de Carga: O k6 foi usado para gerar o tráfego, também rodando em seu próprio contêiner com 2.0 vCPUs e 1GB de RAM.
O Experimento: isolando o I/O para o Teste A/B
O objetivo era criar um cenário 100% I/O-bound para estressar especificamente a capacidade do servidor de gerenciar threads bloqueadas. Para isso, o cache da aplicação foi desabilitado, informando o parâmetro “-e SPRING_CACHE_TYPE=none” no momento das execuções.
Foram executados dois testes de estresse idênticos, de 1 minuto cada, com 50 usuários virtuais (VUs) rodando sem pausa (sleep). A única variável alterada entre os testes foi a configuração de threads do Spring Boot:
- Teste A (Controle): Usando threads de plataforma tradicionais (spring.threads.virtual.enabled=false).
- Teste B (Experimento): Usando Virtual Threads (spring.threads.virtual.enabled=true).
Os resultados: a prova nos números
Os resultados da comparação foram conclusivos e demonstraram um ganho de performance massivo.
Métrica | Sem Virtual Threads (Platform) | Com Virtual Threads (Virtual) | Melhoria |
Vazão (RPS) | ~105 reqs/s | ~136 reqs/s | +29.5% |
Latência Média | 355 ms | 272 ms | -23.4% |
Latência p95 | 794 ms | 508 ms | -36% |
Taxa de Erro | 0.00% | 0.00% | (Estável) |
Os resultados: a prova nos números
Os números mostram que a versão com Virtual Threads processou ~30% mais requisições e foi ~36% mais rápida para 95% dos usuários. A razão para essa diferença dramática está em como os dois modelos de thread lidam com o bloqueio de I/O.
Com Platform Threads, quando uma requisição fazia uma chamada para a API externa (mockada), a thread do servidor ficava bloqueada, ociosa, esperando a resposta. Com 50 usuários concorrentes, o pool limitado de threads do Tomcat rapidamente se esgotava, forçando novas requisições a esperar em uma fila, o que aumentava a latência.
Com Virtual Threads, o cenário muda. Quando uma requisição bloqueava esperando pelo I/O, a thread da plataforma era imediatamente liberada para atender outra requisição. O sistema conseguiu lidar com muito mais requisições “em voo” simultaneamente, resultando em menos tempo de fila, menor latência e uma vazão muito maior.
Conclusão: o futuro é (quase) “grátis”
O experimento demonstra que habilitar as Virtual Threads em aplicações Spring Boot I/O-bound é um dos ganhos de performance mais impactantes e de menor esforço disponíveis no ecossistema Java moderno.
Para serviços que passam a maior parte do tempo esperando por respostas de bancos de dados, outras APIs ou qualquer operação de rede, o Project Loom oferece um aumento de escalabilidade transformador, sem a complexidade de reescrever o código para um paradigma reativo. É, na prática, uma otimização de performance quase “gratuita”, que permite que aplicações síncronas e legíveis escalem como nunca.