Problemi di prestazioni quando si effettuano chiamate a servizi Web da un'applicazione ASP.NET

Questo articolo fornisce assistenza per risolvere i problemi di prestazioni che si verificano quando si effettuano chiamate ai servizi Web da un'applicazione Microsoft ASP.NET.

Versione originale del prodotto: ASP.NET
Numero KB originale: 821268

Sintomi

Quando si effettuano chiamate ai servizi Web da un'applicazione ASP.NET, è possibile che si verifichino contese, prestazioni insufficienti e deadlock. I client possono segnalare che le richieste non rispondono o richiedono molto tempo per l'esecuzione. Se si sospetta un deadlock, il processo di lavoro può essere riciclato.

Quando si effettua una chiamata al metodo, è possibile che venga visualizzato il HttpWebRequest.GetResponse messaggio di errore di eccezione seguente:

"System.InvalidOperationException: i thread liberi nell'oggetto ThreadPool non erano sufficienti per completare l'operazione."

È anche possibile che venga visualizzato il messaggio di errore di eccezione seguente nel browser:

"HttpException (0x80004005): Timeout della richiesta."

Nota

Questo articolo si applica anche alle applicazioni che effettuano HttpWebRequest richieste direttamente.

Causa

Questo problema può verificarsi perché ASP.NET limita il numero di thread di lavoro e thread di porta di completamento che una chiamata può usare per eseguire le richieste.

In genere, una chiamata a un servizio Web usa un thread di lavoro per eseguire il codice che invia la richiesta e un thread di porta di completamento per ricevere il callback dal servizio Web. Tuttavia, se la richiesta viene reindirizzata o richiede l'autenticazione, la chiamata può usare un numero massimo di due thread di lavoro e due thread di porta di completamento. È quindi possibile esaurire l'oggetto gestito ThreadPool quando si verificano più chiamate al servizio Web contemporaneamente.

Si supponga, ad esempio, che l'oggetto ThreadPool sia limitato a 10 thread di lavoro e che tutti i 10 thread di lavoro stiano eseguendo codice in attesa dell'esecuzione di un callback. Il callback non può mai essere eseguito, perché tutti gli elementi di lavoro accodati a vengono bloccati fino a ThreadPool quando non diventa disponibile un thread.

Un'altra potenziale origine di contesa è il maxconnection parametro usato dallo System.Net spazio dei nomi per limitare il numero di connessioni. In genere, questo limite funziona come previsto. Tuttavia, se molte applicazioni tentano di effettuare molte richieste a un singolo indirizzo IP contemporaneamente, i thread potrebbero dover attendere una connessione disponibile.

Risoluzione

Per risolvere questi problemi, è possibile ottimizzare i parametri seguenti nel file Machine.config in base alla situazione:

  • maxWorkerThreads
  • minWorkerThreads
  • maxIoThreads
  • minFreeThreads
  • minLocalRequestFreeThreads
  • maxconnection
  • executionTimeout

Per risolvere correttamente questi problemi, eseguire le azioni seguenti:

  • Limitare il numero di richieste ASP.NET che possono essere eseguite contemporaneamente a circa 12 per CPU.
  • Consentire ai callback del servizio Web di usare liberamente i thread in ThreadPool.
  • Selezionare un valore appropriato per il maxconnections parametro. Basare la selezione sul numero di indirizzi IP e AppDomain usati.

Nota

La raccomandazione di limitare il numero di richieste di ASP.NET a 12 per CPU è leggermente arbitraria. Tuttavia, questo limite si è rivelato efficace per la maggior parte delle applicazioni.

MaxWorkerThreads e maxIoThreads

ASP.NET usa le due impostazioni di configurazione seguenti per limitare il numero massimo di thread di lavoro e di completamento usati:

<processModel maxWorkerThreads="20" maxIoThreads="20">

Il maxWorkerThreads parametro e il maxIoThreads parametro vengono moltiplicati in modo implicito per il numero di CPU. Ad esempio, se si dispone di due processori, il numero massimo di thread di lavoro è 2 * maxWorkerThreads.

MinFreeThreads e minLocalRequestFreeThreads

ASP.NET contiene anche le impostazioni di configurazione seguenti che determinano quanti thread di lavoro e thread di porta di completamento devono essere disponibili per avviare una richiesta remota o una richiesta locale:

<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">

Se non sono disponibili thread sufficienti, la richiesta viene accodata fino a quando non sono disponibili thread sufficienti per effettuare la richiesta. Pertanto, ASP.NET non eseguirà contemporaneamente più del numero di richieste seguente:

(maxWorkerThreads * numero di CPU) - minFreeThreads

Nota

Il minFreeThreads parametro e il minLocalRequestFreeThreads parametro non vengono moltiplicati in modo implicito per il numero di CPU.

MinWorkerThreads

ASP.NET contiene anche l'impostazione di configurazione seguente che determina il numero di thread di lavoro che possono essere resi immediatamente disponibili per gestire una richiesta remota.

<processModel minWorkerThreads="1">

I thread controllati da questa impostazione possono essere creati a una velocità molto più veloce rispetto ai thread di lavoro creati dalle funzionalità predefinite di ottimizzazione dei thread di Common Language Runtime (CLR).

Questa impostazione consente a ASP.NET di gestire le richieste che potrebbero riempire improvvisamente la coda delle richieste ASP.NET a causa di un rallentamento in un server back-end, un improvviso burst di richieste dall'estremità client o qualcosa di simile che causerebbe un improvviso aumento del numero di richieste nella coda.

Il valore predefinito per il minWorkerThreads parametro è 1. È consigliabile impostare il valore per il minWorkerThreads parametro sul valore seguente:

minWorkerThreads = maxWorkerThreads / 2

Per impostazione predefinita, il minWorkerThreads parametro non è presente nel file Web.config o nel file Machine.config . Questa impostazione viene moltiplicata in modo implicito per il numero di CPU.

Maxconnection

Il maxconnection parametro determina il numero di connessioni che possono essere effettuate a un indirizzo IP specifico. Il parametro viene visualizzato come segue:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://65.53.32.230" maxconnection="12">
</connectionManagement>

Se il codice dell'applicazione fa riferimento all'applicazione in base al nome host anziché all'indirizzo IP, il parametro deve essere visualizzato come segue:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname" maxconnection="12">
</connectionManagement>

Infine, se l'applicazione è ospitata su una porta diversa da 80, il parametro deve includere la porta non standard nell'URL, simile alla seguente:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname:8080" maxconnection="12">
</connectionManagement>

Le impostazioni per i parametri illustrati in precedenza in questo articolo sono tutte a livello di processo. Tuttavia, l'impostazione del maxconnection parametro si applica al livello AppDomain. Per impostazione predefinita, poiché questa impostazione si applica al livello AppDomain, è possibile creare un massimo di due connessioni a un indirizzo IP specifico da ogni AppDomain nel processo.

Executiontimeout

ASP.NET usa l'impostazione di configurazione seguente per limitare il tempo di esecuzione della richiesta:

<httpRuntime executionTimeout="90"/>

È anche possibile impostare questo limite usando la Server.ScriptTimeout proprietà .

Nota

Se si aumenta il valore del executionTimeout parametro, potrebbe essere necessario modificare anche l'impostazione del processModelresponseDeadlockInterval parametro.

Suggerimenti

Le impostazioni consigliate in questa sezione potrebbero non funzionare per tutte le applicazioni. Tuttavia, le informazioni aggiuntive seguenti possono essere utili per apportare le modifiche appropriate.

Se si effettua una chiamata di servizio Web a un singolo indirizzo IP da ogni pagina ASPX, Microsoft consiglia di usare le impostazioni di configurazione seguenti:

  • Impostare i valori del maxWorkerThreads parametro e del parametro su maxIoThreads100.
  • Impostare il valore del parametro su maxconnection12*N (dove N è il numero di CPU disponibili).
  • Impostare i valori del parametro su minFreeThreads88*N e il parametro su minLocalRequestFreeThreads76*N.
  • Impostare il valore di minWorkerThreads su 50. Tenere presente che minWorkerThreads non si trova nel file di configurazione per impostazione predefinita. È necessario aggiungerlo.

Alcune di queste raccomandazioni prevedono una formula semplice che prevede il numero di CPU in un server. La variabile che rappresenta il numero di CPU nelle formule è N.

Per queste impostazioni, se l'hyperthreading è abilitato, è necessario usare il numero di CPU logiche anziché il numero di CPU fisiche. Ad esempio, se si dispone di un server a quattro processori con hyperthreading abilitato, il valore di N nelle formule sarà 8 anziché 4.

Nota

Quando si usa questa configurazione, è possibile eseguire un massimo di 12 richieste di ASP.NET per CPU contemporaneamente perché 100-88=12. Di conseguenza, almeno 88*N thread di lavoro e 88*N thread di porta di completamento sono disponibili per altri usi,ad esempio per i callback del servizio Web.

Ad esempio, è disponibile un server con quattro processori e l'hyperthreading abilitato. In base a queste formule, si userebbero i valori seguenti per le impostazioni di configurazione indicate in questo articolo.

<system.web>
    <processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
    <httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608"/>
</system.web>
<system.net>
    <connectionManagement>
        <add address="[ProvideIPHere]" maxconnection="96"/>
    </connectionManagement>
</system.net>

Inoltre, quando si usa questa configurazione, sono disponibili 12 connessioni per CPU per indirizzo IP per ogni AppDomain. Di conseguenza, nello scenario seguente si verifica una contesa molto limitata quando le richieste sono in attesa di connessioni e l'oggetto ThreadPool non è esaurito:

  • Il Web ospita solo un'applicazione (AppDomain).
  • Ogni richiesta per una pagina ASPX effettua una richiesta di servizio Web.
  • Tutte le richieste si trovano nello stesso indirizzo IP.

Tuttavia, quando si usa questa configurazione, gli scenari che coinvolgono uno dei seguenti useranno probabilmente un numero eccessivo di connessioni:

  • Le richieste riguardano più indirizzi IP.
  • Le richieste vengono reindirizzate (codice di stato 302).
  • Le richieste richiedono l'autenticazione.
  • Le richieste vengono effettuate da più AppDomain.

In questi scenari è consigliabile usare un valore inferiore per il maxconnection parametro e valori superiori per il minFreeThreads parametro e il minLocalRequestFreeThreads parametro .

Ulteriori informazioni

Per altre informazioni, vedere Miglioramento delle prestazioni ASP.NET.

Se si verificano prestazioni e contese scarse in IIS insieme a ASP.NET, visitare i blog Microsoft seguenti: