Arquitetura Backend

O que é e quando usar Spring Webflux

O significa o Spring Webflux, como utilizá-la e qual a vantagem dessa programação reativa, assíncrona e não bloqueante.

Veja o significa o Spring Webflux, como utilizá-la e qual a vantagem dessa programação reativa, assíncrona e não bloqueante.

Para começar, vamos analisar o modelo de processamento utilizado pelo Spring MVC

O Spring MVC, que utiliza por padrão o Tomcat como servidor, implementa o conceito de Thread-per-Request, onde para cada requisição que o serviço recebe é atribuída uma thread. Esta thread controla todo fluxo do processamento, desde o inicio da requisição até o retorno para o cliente. Veja:

Mas vamos imaginar o seguinte cenário: um serviço conta-service que disponibiliza um endpoint para consulta de extrato da conta. Porém, leva 5 segundos para consultar todo o banco de dados. Caso nosso serviço receba 300 consultas simultâneas (considerando que estamos utilizando o default de 200 threads no pool) perderíamos 100 dessas requisições por não conseguir processá-las.

Para solucionar este problema podemos adotar algumas soluções:

  1. Aumentar o pool de threads – Essa abordagem pode resolver por algum tempo, mas não temos como saber o número mágico que irá resolver todos problemas. Podemos aumentar para 400 o pool de thread, mas e se o serviço receber uma carga de 500? O sistema vai ser afetado novamente. E, além disso, quanto mais thread maior será o consumo de memória.
  2. Aumentar o número de instâncias do serviço – Com essa abordagem conseguimos solucionar o problema, podendo, inclusive, implementar alguma solução de auto escalonamento para incluir mais recursos quando necessário. Porém só conseguiríamos um escalonamento horizontal. É ai que o Spring Webflux pode nos ajudar.

Spring MVC Requisição Bloqueante 

Quando uma requisição chega ao serviço, é solicitado uma thread do pool para realizar o processamento I/O desta requisição – como por exemplo, consulta ao banco de dados, consulta um serviço externo, etc. Durante o tempo que a consulta ao banco está sendo realizada, a thread permanece bloqueada e não pode ser utilizada para outro processamento.

Spring Webflux Requisição Não Bloqueante

O Spring Webflux implementa o paradigma reativo, que se refere a programação orientada a mudanças – por isso não mais bloqueante. Agora, em vez de bloquear a thread esperando o fim de um processo I/O, a thread é liberada após solicitar o processamento e quando formos notificados sobre o fim da operação o sistema vai “reagir” a essa notificação. O conceito de reatividade não é algo novo – aquela formula que você faz no Microsoft Excel aplica este o conceito.

Vamos, por exemplo, considerar o calculo de dividir o valor de um jantar entre a quantidade de pessoas presentes. Podemos usar a formula = A2 / B2 aplicada na coluna C2. Sempre que fossemos alterar o valor do jantar, ou a quantidade de pessoas, a coluna C2 vai ser recalculada automaticamente de forma assíncrona.

Com o Spring Webflux, as threads são notificadas sempre que existe algum trabalho para fazer, sem ficar aguardando o estado de conclusão do processo. Geralmente temos apenas uma thread por core de CPU controlando o chamado “eventloop”, por isso se torna extremamente importante não bloquear os processos – caso contrario vamos passar pelo mesmo problema apresentado no modelo anterior.

EventLoop

Todas as requisições que o socket recebe são salvas em uma fila de evento (Event Queue). O Eventloop monitora essa fila e processa cada item de forma sequencial, repassando a execução para uma outra worker thread. Por isso é importante a utilização de driver reativos que recebam esta requisição e, após o fim do processamento, enviem o retorno para a fila de eventos para ser processado pelo EventLoop.

Se voltarmos ao nosso exemplo do conta-service, como funcionaria o processamento com Spring Webflux?

1. Toda nova requisição seria salva na fila de eventos;

2. EventLoop de forma sequencial pega cada item da fila;

3. Por se tratar de uma consulta de banco de dados, o EventLoop envia a requisição para uma worker thread do driver de banco e pega outro item da fila de eventos para processar;

4. Ao final da consulta ao banco a worker thread envia o retorno dos dados para a fila de eventos;

5. EventLoop processa o item de retorno e envia o resultado para o cliente.

Programação Reativa

A programação reativa é baseada no padrão Observable. É basicamente onde um consumidor precisa se associar a um produtor para assim receber os dados ao final do processamento.

  • Publisher: é o responsável por emitir os dados para os seus assinantes.
  • Subscriber: é quem se associa para receber os dados emitidos pelo publisher.
  • Subscription: é quem define o relacionamento entre publisher e subscriber. Através dele é feito a solicitação de dados e também o cancelamento do fluxo.

O publisher só irá executar o fluxo quando algum cliente se inscrever, e nesse momento que acontece alguma das dávidas relacionadas ao webflux. Para o publisher executar de fato, podemos nos inscrever explicitamente (subscribe) ou utilizando o “return” que, por baixo o Spring Webflux, realiza a inscrição automaticamente.

O Spring Webflux apresenta diversas vantagens, como otimização de recursos, baixa utilização de memória e backprassure. Porém ele não é uma bala de prata. Em cenários onde o serviço trabalha com leitura/escrita de arquivos em disco ou vai utilizar drivers não reativos o melhor caminho é utilizar uma serviço não reativo. 

E lembre-se: nunca bloqueie uma thread. Caso seu serviço utilize Spring Webflux e agora precisa conectar em uma lib não reativa, estude os conceitos de schedulers, para não causar bloqueios no eventLoop.

%d blogueiros gostam disto: