Ao fazer chamadas para os serviços Web em XML por um
aplicativo ASP.NET, você talvez enfrente contenção, mau desempenho e deadlocks.
Talvez os clientes informem que as solicitações param de responder (ou
"travam") ou demoram muito para serem executadas. Caso um deadlock seja
suspeito, é possível que o processo de trabalho seja reciclado. As seguintes
mensagens no log de eventos do aplicativo podem ser exibidas.
- Caso esteja usando o IIS 5.0 (Serviços de Informações da
Internet da Microsoft), as seguintes mensagens no log de eventos do aplicativo
podem ser exibidas:
Tipo de evento: Erro
Origem do evento: ASP.NET 1.0.3705.0
Categoria: Nenhuma
Identificação do evento: 1003
Data: 5/4/2003
Hora: 6:18:23 PM
Usuário: N/A
Computador: <Nome_do_Computador>
Descrição:
aspnet_wp.exe (PID: <xxx>) foi reciclado porque era suspeito de estar em um estado de deadlock.
Ele não enviou nenhuma resposta para solicitações pendentes nos últimos 180 segundos. - Caso esteja usando o IIS 6.0, as seguintes mensagens no log
de eventos do aplicativo podem ser exibidas:
Tipo de evento: Aviso
Origem do evento: W3SVC-WP
Categoria: Nenhuma
Identificação do evento: 2262
Data: 5/4/2003
Hora: 1:02:33 PM
Usuário: N/A
Computador: <Nome_do_Computador>
Descrição:
ISAPI 'C:\Windows\Microsoft.net\Framework\v.1.1.4322\aspnet_isapi.dll' informou ter
problemas pelo seguinte motivo: 'Deadlock detectado'. - Caso esteja usando o IIS 6.0, as seguintes mensagens no log
de eventos do Sistema podem ser exibidas:
Tipo de evento: Aviso
Origem do evento: W3SVC
Categoria: Nenhuma
Identificação do evento: 1013
Data: 5/4/2003
Hora: 1:03:47 PM
Usuário: N/A
Computador: <Nome_do_Computador>
Descrição:
Um processo que atendia o pool de aplicativos 'DefaultAppPool' excedeu o tempo-limite durante o desligamento.
A identificação do processo era '<xxxx>'.
A seguinte mensagem de erro de exceção ao fazer uma chamada para
o método pode ser exibida
HttpWebRequest.GetResponse:
?System.InvalidOperationException: Não
havia threads livres o suficiente no objeto ThreadPool para concluir a
operação.?
A seguinte mensagem de erro de exceção no navegador também
pode ser exibida:
?HttpException (0x80004005): A
solicitação expirou.?
Observação Este artigo também se aplica a aplicativos que façam solicitações
HttpWebRequest diretamente.
Este problema pode ocorrer porque o ASP.NET limita o número
de threads de trabalho e de threads de porta de conclusão que uma chamada pode
usar na execução de solicitações.
Normalmente, uma chamada para um
serviço da Web usa um thread de trabalho na execução do código que envia a
solicitação e um thread de porta de conclusão na recepção do retorno de chamada
proveniente do serviço da Web. No entanto, caso a solicitação seja
redirecionada ou exija autenticação, a chamada pode usar dois threads de
trabalho e dois threads de porta de conclusão. Por isso, é possível usar todo o
ThreadPool gerenciado quando ocorrem várias chamadas de serviço da Web ao mesmo
tempo.
Por exemplo, vamos supor que o ThreadPool esteja limitado a 10
threads de trabalho e que todos os 10 estejam executando um código que está
aguardando um retorno de chamada para ser executado. O retorno de chamada
jamais poderá ser executado porque todos os itens de trabalho enfileirados no
ThreadPool estarão bloqueados até que um thread esteja
disponível.
Outra possível origem de contenção é o parâmetro
maxconnection usado pelo namespace
System.Net na limitação do número de conexões. Geralmente, o limite funciona
conforme o esperado. No entanto, caso muitos aplicativos tentem fazer muitas
solicitações para um único endereço IP ao mesmo tempo, os threads talvez tenham
de aguardar uma conexão disponível.
Para resolver estes problemas, é possível ajustar os
seguintes parâmetros no arquivo Machine.config de acordo com a sua situação:
- maxWorkerThreads
- minWorkerThreads
- maxIoThreads
- minFreeThreads
- minLocalRequestFreeThreads
- maxconnection
- executionTimeout
Para resolver os problemas com êxito, faça o seguinte:
- Limite o número de solicitações ASP.NET que podem ser
executadas ao mesmo tempo para aproximadamente 12 por CPU.
- Permita que os retornos de chamada do serviço da Web usem
threads livremente no ThreadPool.
- Selecione um valor apropriado para o parâmetro maxconnections. Basicamente, a seleção deve ter base no número de endereços IP e
de AppDomains que são usados.
Observação A recomendação para limitar o número de solicitações ASP.NET para
12 por CPU é um pouco arbitrária. No entanto, o limite mostrou funcionar bem
para a maioria dos aplicativos.
maxWorkerThreads e maxIoThreads
O ASP.NET usa estas duas configurações para limitar o
número máximo de threads de trabalho e de threads de conclusão usados:
<processModel maxWorkerThreads="20" maxIoThreads="20">
Os parâmetros
maxWorkerThreads e
maxIoThreads são implicitamente multiplicados pelo número de CPUs. Por
exemplo, caso você tenha dois processadores, o número máximo de threads de
trabalho é o seguinte:
2*maxWorkerThreads
minFreeThreads e minLocalRequestFreeThreads
O ASP.NET também contém as seguintes configurações
que determinam quantos threads de trabalho e threads de porta de conclusão
devem estar disponíveis para iniciar uma solicitação remota ou uma solicitação
local:
<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">
Caso não haja threads disponíveis o suficiente, a solicitação é
enfileirada até que threads suficientes estejam livres para fazer a
solicitação. Por isso, o ASP.NET não executará mais do que o seguinte número de
solicitações ao mesmo tempo:
(maxWorkerThreads*número_de_CPUs)-minFreeThreads
Observação Os parâmetros
minFreeThreads e
minLocalRequestFreeThreads não são multiplicados implicitamente pelo número de CPUs.
minWorkerThreads
Assim como o ASP.NET 1.0 Service Pack 3 e o ASP.NET
1.1, o ASP.NET também contém a seguinte configuração que determina quantos
threads de trabalho podem ser disponibilizados imediatamente para atender uma
solicitação remota.
<processModel minWorkerThreads="1">
Threads controlados pela configuração podem ser criados muito mais
rapidamente do que threads de trabalho que foram criados por recursos padrão de
"ajuste de threads" do CLR. A configuração permite que o ASP.NET atenda
solicitações que talvez estejam enchendo a fila de solicitações ASP.NET,
talvez, devido a uma redução em um servidor back-end, uma intermitência
repentina de solicitações do lado do cliente ou algo semelhante que causaria um
aumento repentino no número de solicitações na fila. O valor padrão do
parâmetro
minWorkerThreads é 1. É aconselhável que você defina o valor do parâmetro
minWorkerThreads para o seguinte valor.
minWorkerThreads = maxWorkerThreads / 2
Por padrão, o parâmetro
minWorkerThreads não está presente nos arquivos Web.config ou Machine.config. A
configuração é multiplicada implicitamente pelo número de CPUs.
maxconnection
O parâmetro
maxconnection determina quantas conexões podem ser feitas a um endereço IP
específico. O parâmetro aparece da seguinte forma:
<connectionManagement>
<add address="*" maxconnection="2">
<add address="65.53.32.230" maxconnection="12">
</connectionManagement> As configurações para os parâmetros descritos anteriormente neste
artigo estão todas no nível de processamento. No entanto, a configuração do
parâmetro
maxconnection se aplica ao nível AppDomain. Por padrão, como a configuração se
aplica ao nível AppDomain, é possível criar um máximo de duas conexões para um
endereço IP específico de cada AppDomain no processo.
executionTimeout
O ASP.NET usa a seguinte configuração para limitar o
tempo de execução da solicitação:
<httpRuntime executionTimeout="90"/>
Também é possível definir o limite, usando a propriedade
Server.ScriptTimeout.
Observação Caso aumente o valor do parâmetro
executionTimeout, talvez você também precise modificar a configuração do parâmetro
processModel responseDeadlockInterval.
Recomendações
As configurações recomendadas nesta seção talvez não funcionem em
todos os aplicativos. No entanto, as seguintes informações adicionais talvez
ajudem você a fazer os ajustes apropriados.
Caso esteja fazendo uma
chamada de serviço da Web para um único endereço IP por meio de cada uma das
páginas ASPX, a Microsoft recomenda que você use as seguintes configurações:
- Defina os valores dos parâmetros maxWorkerThreads e maxIoThreads para 100.
- Defina o valor do parâmetro maxconnection para 12*N (em que N é o número de CPUs
existente).
- Defina os valores do parâmetro minFreeThreads para 88*N e do parâmetro minLocalRequestFreeThreads para 76*N.
- Defina o valor de minWorkerThreads para 50. Lembre-se de que minWorkerThreads não está no arquivo de configuração por padrão. É necessário
adicioná-lo.
Algumas das recomendações envolvem uma fórmula simples que
envolve o número de CPUs em um servidor. A variável que representa o número de
CPUs nas fórmulas é
N. Para as configurações, caso
tenha o hyperthreading habilitado, você deve usar o número de CPUs lógicas, e
não o número de CPUs físicas. Por exemplo, se tiver um servidor de quatro
processadores com o hyperthreading habilitado, o valor de
N nas fórmulas será
8, e não
4.
Observação Ao usar esta configuração, é possível executar um máximo de 12
solicitações de ASP.NET por CPU ao mesmo tempo porque
100-88=12. Por isso, há pelo menos 88*
N threads
de trabalho e 88*
N threads de porta de conclusão
disponíveis para outros usos (como, por exemplo, retornos de chamada do serviço
da Web).
Por exemplo, você tem um servidor de quatro processadores e
com o hyperthreading habilitado. Com base nas fórmulas, você usaria os
seguintes valores nas configurações mencionadas neste artigo.
<processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50">
<httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608">
<connectionManagement>
<add address="[ProvideIPHere]" maxconnection="96"/>
</connectionManagement>
Além disso, ao usar esta configuração, há 12 conexões disponíveis
por CPU por endereço IP para cada AppDomain. Por isso, na seguinte situação
ocorre pouquíssima contenção, quando as solicitações estão aguardando conexões,
e o ThreadPool não é usado totalmente:
- A Web hospeda somente um aplicativo (AppDomain).
- Todas as solicitações para uma página ASPX criam uma
solicitação de serviço da Web.
- Todas as solicitações são para o mesmo endereço
IP.
No entanto, ao usar esta configuração, as seguintes situações
provavelmente usarão muitas conexões:
- As solicitações são para vários endereços IP.
- As solicitações são redirecionadas (código de status
302).
- As solicitações exigem autenticação.
- As solicitações são feitas a partir de vários
AppDomains.
Nestas situações, é uma boa idéia usar um número menor para o
parâmetro
maxconnection e valores maiores para os parâmetros
minFreeThreads e
minLocalRequestFreeThreads.