Através deste artigo, explicaremos principalmente os problemas encontrados no processamento assíncrono Servlet 3.0 no desenvolvimento de Java e nas soluções. A seguir, estão os conteúdos específicos:
O Servlet 3.0 começou a fornecer o AsyncContext para oferecer suporte ao processamento assíncrono de solicitações. Então, quais benefícios podem processamento assíncrono de solicitações?
De um modo geral, a maneira como os contêineres da web lidam com as solicitações é atribuir um thread a cada solicitação. Todos sabemos que a criação de threads não é sem custo e o pool de threads de contêineres da web tem um limite superior.
Um problema muito previsível é que, sob condições de carga alta, o pool de threads está ocupado; portanto, a solicitação subsequente só pode ser esperada. Se você não tiver sorte, o cliente reportará um erro de tempo limite em espera.
Antes de aparecer o AsyncContext, a única maneira de resolver esse problema era expandir o pool de threads do contêiner da web.
Mas ainda há um problema com isso, considere os seguintes cenários:
Existe um contêiner da web com um tamanho de pool de threads de 200. Existe um aplicativo da web com dois servlets, o tempo que leva o servlet-a para lidar com uma única solicitação é 10s e o tempo necessário para o servlet-b para lidar com uma única solicitação é 1s.
Agora, encontramos uma carga alta, com mais de 200 solicitações ao Servlet-A. Se o servlet-b for solicitado neste momento, esperaremos porque todos os threads HTTP foram ocupados pelo Servlet-A.
Nesse momento, o engenheiro descobriu o problema e expandiu o tamanho do pool de threads para 400, mas a carga continuou a subir. Agora, existem 400 solicitações para o Servlet-A, e o Servlet-B ainda não pode responder.
Você viu o problema? Como o thread HTTP e o thread do trabalhador são acoplados, ele preencherá o thread HTTP quando um grande número de solicitações forem feitos para uma operação demorada, resultando em todo o contêiner da Web não conseguir responder.
No entanto, se usarmos asyncContext, podemos entregar a operação demorada a outro thread, para que o thread HTTP seja lançado e possamos lidar com outras solicitações.
Observe que apenas o uso do AsyncContext pode alcançar o efeito mencionado acima. Se você usar diretamente o novo thread () ou métodos similares, o thread http não será retornado ao contêiner.
Aqui está um exemplo oficial:
@WebServlet (urlpatterns = {"/asyncServlet"}, assíncsupported = true) classe pública AsyncServlet estende httpServlet {/ * ... mesmas variáveis e método init como em syncservlet ... */@override vazio público (HTPSTRETRETRETRETRETRETRETRETRETRETLET (HTTSTELTRETLET como em SyncServlet ... */@Override Public Void do do do doget (httStlestlettrettlet (httStlestlestlet (httStlestlestlet como em syncsertlet ... */@override vazio público. Response.setContentType ("Texto/html; charset = utf-8"); final asyncContext acontext = request.startasync (); achentext.start (new runnable () {public void run () {string param = acontext.getRequest (). getParameter ("param"); string result = Resource.Process (param); httpServLeTResponse Respons = aconTextTextResponse (); / * ... Print para a resposta ... *; }} armadilha
Neste exemplo oficial, cada thread http abrirá outro thread trabalhador para processar a solicitação e, em seguida, retornará o thread HTTP ao contêiner da web. Mas veja o javadoc do método asyncContext.start ():
Faz com que o contêiner envie um thread, possivelmente de um pool de threads gerenciado, para executar o Runnable especificado.
De fato, não há regulamentação aqui de onde o tópico trabalhador vem. Talvez seja outro pool de threads que não seja o pool de threads http? Ou é apenas um pool de threads http?
A utilidade limitada do artigo asyncContext.start () lê: Diferentes contêineres da Web têm implementações diferentes para isso, mas o Tomcat realmente usa o HTTP Thread Pool para lidar com asyncContext.start ().
Isso significa que originalmente queríamos lançar o thread http, mas na verdade não, porque o thread http ainda é usado como thread do trabalhador, mas esse thread não é o mesmo que o thread http que recebe a solicitação.
Também podemos ver essa conclusão através da referência JMeter de AsyncServlet1 e SyncServlet, e os resultados da taxa de transferência dos dois são semelhantes. Método Iniciar: Inicie Main e, em seguida, use o JMeter para iniciar o Benchmark.jmx (http thread pool = 200 sob a configuração padrão do Tomcat).
Usando ExecutorService
Vi anteriormente que o Tomcat não mantém o pool de threads de trabalhadores separadamente, por isso precisamos encontrar uma maneira de fazer isso sozinhos, ver asyncServlet2, que usa um executores Service com o pool de threads para lidar com o AsyncContext.
Outras maneiras
Portanto, não há maneira fixa de usar asyncContext. Você pode usar métodos diferentes para lidar com isso de acordo com as necessidades reais. Por esse motivo, você precisa de algum conhecimento da programação simultânea de Java.
Mal -entendido do desempenho
O objetivo do AsyncContext não é melhorar o desempenho, nem fornece diretamente a melhoria do desempenho. Ele fornece um mecanismo para dissipar o thread HTTP e o thread do trabalhador, melhorando assim a capacidade de resposta dos contêineres da Web.
No entanto, o AsyncContext pode melhorar o desempenho em algum momento, mas isso depende de como seu código é escrito.
Por exemplo: o número de pools de threads HTTP em um contêiner da Web é 200 e um servlet usa um pool de threads de 300 trabalhadores para lidar com o AsyncContext.
Comparado com o pool de threads do Sync Method Method Worker = HTTP Thread Pool = 200, neste caso, temos um pool de threads de trabalhador de 300, para que ele definitivamente trará algumas melhorias de desempenho (afinal, há mais pessoas trabalhando).
Pelo contrário, se o número de threads do trabalhador for <= o número de threads http, não haverá melhoria de desempenho, porque o gargalo para solicitações de processamento está no thread do trabalhador.
Você pode modificar o tamanho do pool de threads do ASYNCSERVlet2 e compará -lo com os resultados do SyncServlet Benchmark para verificar essa conclusão.
Não pense que o pool de threads do trabalhador deve ser maior que o pool de threads HTTP. As razões são as seguintes:
As duas responsabilidades são diferentes. Uma é que o contêiner da web é usado para receber solicitações externas e o outro é processar a lógica de negócios.
Criar tópicos tem um custo. Se o pool de threads HTTP já for grande, a criação de um pool de threads de trabalhador maior causará muita troca de contexto e sobrecarga de memória.
O objetivo do AsyncContext é liberar o thread HTTP para evitar o uso de operações a longo prazo e, assim, fazer com que o contêiner da Web não possa responder.
Portanto, na maioria dos casos, o pool de threads de trabalhadores não será muito grande, e diferentes pools de threads de trabalhadores serão construídos de acordo com diferentes empresas.
Por exemplo: o tamanho do pool de threads de contêineres da web é de 200 e o tamanho do pool de threads de trabalhadores é 10 para um servlet lento. Dessa forma, não importa quantas solicitações sejam usadas para retardar operações, ele não preencherá o thread HTTP e fará com que outras solicitações não possam processar.