Gerenciando pool de threads no Spring Boot

A cada dia que passa precisamos trabalhar mais com funcionalidades assíncronos, onde há uma maior preocupação com escalabilidade, performance, entre outros requisitos visando atender as características reativas. Porém como gerenciar os métodos assíncronos? Como controlar e monitorar a quantidade de threads criadas a cada requisição?

Basicamente é possível gerenciar funcionalidade assíncrona configurando pools de threads, onde é possível limitar a quantidade de processos sendo executados em paralelo, monitorar o tamanho do pool entre outras possibilidades.

Exemplificando, deixar um método assíncrono em uma aplicação Spring é simplesmente anotar ele como @Async, assim ele deixará de bloquear sua chamada e continuará sua execução em “background”.

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class ProcessorService {

    @Async
    public void process(InputStreamReader inputStreamReader, String fileName) throws IOException {
        // processa o arquivo
   }
}

Porém qual o possível problema dessa abordagem? Esse método não possui nenhum controle, então caso requisitado inúmeras vezes, a aplicação vai criar inúmeras threads, assim podendo comprometer o desempenho do restante da aplicação.

Com isso, podemos configurar um ThreadPoolTaskExecutor para gerenciar o pool de threads de terminado método, onde é possível configurar o tamanho máximo de threads que vão ser executadas em paralelos, assim controlando a quantidade de execução e minimizando o impacto no restante da aplicação.

No Spring Boot, essa configuração é basicamente ativar o @EnableAsync e criar um bean configurando e inicializando um ThreadPoolTaskExecutor, como no exemplo abaixo, que é configurado que o pool do fileExecutor é de até 3 threads simultâneas:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@SpringBootApplication
@EnableAsync
public class AppConfig {

    public static void main(String[] args) {
        SpringApplication.run(AppConfig.class, args);
    }

    @Bean(name = "fileExecutor")
    public Executor asyncExecutor() {
        final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(3);
        executor.initialize();
        return executor;
    }
}
  • @EnableAsync: Habilita as funcionalidades assíncronas no Spring, permitindo configuras as task;
  • ThreadPoolTaskExecutor: Classe para gerência e monitorar determinado pool;
  • executor.setCorePoolSize: Configura o tamanho do pool;
  • executor.setMaxPoolSize: Limita a quantidade máxima de threads em paralelo;
  • executor.initialize: Executa o taskExecutor

Há outras propriedades e métodos no na configuração do ThreadPoolTaskExecutor.

Feito a configuração do bean de configuração do ThreadPoolTaskExecutor é necessário referenciar o nome do bean na anotação do @Async, caso não referenciado será utilizado a configuração default.

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class ProcessorService {

    @Async("fileExecutor")
    public void process(InputStreamReader inputStreamReader, String fileName) throws IOException {
        // processa o arquivo
   }
}

Observação: Mais de um método pode ser associado no mesmo ThreadPoolTaskExecutor, assim eles vão dividir o mesmo pool.

Baseado nisso, o ThreadPoolTaskExecutor é uma boa solução para termos mais controle e monitoramento dos métodos assíncronos nas nossas aplicações Spring Boot, onde podemos limitar a quantidade máxima de processos sendo executados em paralelo, assim controlando o impacto no restante da aplicação ou até mesmo limitando o tamanho para um e garantindo uma única execução por vez.

Anúncios

2 comentários sobre “Gerenciando pool de threads no Spring Boot

  1. Caro, Emmanuel, tenho um servico RSTFULL com o Spring onde eu recebo um arquivo, processo o mesmo e gravo no banco de dados! esse método que é um POST recebe arquivos de varias lojas e ao mesmo tempo, em alguns momentos tenho centenas de Thread abertas fazendo o processamento e gravação do arquivo!

    Posso usar essa sua dica para isso?
    que resposta a aplicação na loja vai receber caso tenha alcançado o limite máximo de Thread?

    Curtir

    • Olá Fred,

      Sim, cabe essa abordagem de limitar o pool de threads nesse seu contexto, caso seja necessário, pois, o benefício de adotar esse limite é controlar a quantidade de threads abertas e evitar que o restante da aplicação sofra impacto.

      A resposta da aplicação vai depender da estratégia que você adotar na chamada do seu serviço (o qual é gerenciado pelo thread pool), se for síncrono a resposta vai aguardar seu processamento e se for assíncrono vai retornar um OK e a requisição vai ser enfileirado no pool de threads.

      Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s