ID do artigo: 821268 - Última revisão: quarta-feira, 20 de dezembro de 2006 - Revisão: 7.2

Contenção, mau desempenho e deadlocks ao fazer solicitações de serviço Web pelos aplicativos ASP.NET

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sintomas

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.

Causa

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.

Resolução

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.

Situação

Este comportamento é próprio do projeto.

Referências

Para obter informações adicionais, visite o seguinte site da Microsoft Developer Network (MSDN) (em inglês):
http://msdn.microsoft.com/library/en-us/dnpag/html/scalenetchapt06.asp (http://msdn.microsoft.com/library/en-us/dnpag/html/scalenetchapt06.asp)

A informação contida neste artigo aplica-se a:
  • Microsoft ASP.NET 1.1
  • Microsoft ASP.NET 1.0
Palavras-chave: 
kbprb KB821268