Problemi di prestazioni quando si effettuano chiamate ai servizi Web da un'applicazione ASP.NET
Questo articolo fornisce informazioni utili 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 conflitti, prestazioni scarse 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 potrebbe essere riciclato.
È possibile che venga visualizzato il seguente messaggio di errore di eccezione quando si effettua una chiamata al HttpWebRequest.GetResponse
metodo :
"System.InvalidOperationException: non sono presenti thread liberi sufficienti nell'oggetto ThreadPool per completare l'operazione".
È anche possibile ricevere il seguente messaggio di errore di eccezione nel browser:
"HttpException (0x80004005): timeout della richiesta."
Note
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 fino a 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 sia ThreadPool
limitato a 10 thread di lavoro e che tutti i 10 thread di lavoro siano attualmente in esecuzione 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 conflitti è 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 per adattarsi al meglio alla situazione:
maxWorkerThreads
minWorkerThreads
maxIoThreads
minFreeThreads
minLocalRequestFreeThreads
maxconnection
executionTimeout
Per risolvere correttamente questi problemi, eseguire le azioni seguenti:
- Limitare il numero di richieste di 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.
Note
È consigliabile limitare il numero di richieste di ASP.NET a 12 per CPU. Tuttavia, questo limite ha dimostrato di funzionare correttamente 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 thread 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 il numero di thread di lavoro e di porte di completamento che 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
Note
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 disponibili immediatamente per il servizio di 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 di ASP.NET alle richieste di servizio che potrebbero improvvisamente riempire la coda di richieste ASP.NET a causa di un rallentamento in un server back-end, di un improvviso burst di richieste dalla fine del client o di un aumento improvviso 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 descritti 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à .
Note
Se si aumenta il valore del executionTimeout
parametro, potrebbe anche essere necessario modificare l'impostazione del processModel
responseDeadlockInterval
parametro.
Consigli
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 al 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 ilmaxIoThreads
parametro su 100. - Impostare il valore del
maxconnection
parametro su 12*N (dove N è il numero di CPU disponibili). - Impostare i valori del
minFreeThreads
parametro su 88*N e ilminLocalRequestFreeThreads
parametro su 76*N. - Impostare il valore di
minWorkerThreads
su 50. Tenere presente cheminWorkerThreads
non si trova nel file di configurazione per impostazione predefinita. È necessario aggiungerlo.
Alcune di queste raccomandazioni includono una semplice formula che implica il numero di CPU in un server. La variabile che rappresenta il numero di CPU nelle formule è N.
Per queste impostazioni, se è abilitato l'hyperthreading, è 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.
Note
Quando si usa questa configurazione, è possibile eseguire un massimo di 12 ASP.NET richieste per CPU contemporaneamente perché 100-88=12. Pertanto, 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, si dispone di un server con quattro processori e hyperthreading abilitati. In base a queste formule, usare 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 ogni indirizzo IP per ogni AppDomain. Pertanto, nello scenario seguente, si verifica molto poco contesa quando le richieste sono in attesa di connessioni e non ThreadPool
viene esaurito:
- Il Web ospita solo un'applicazione (AppDomain).
- Ogni richiesta per una pagina ASPX effettua una richiesta di servizio Web.
- Tutte le richieste vengono inviate allo stesso indirizzo IP.
Tuttavia, quando si usa questa configurazione, gli scenari che coinvolgono una delle connessioni seguenti probabilmente useranno troppe connessioni:
- Le richieste vengono inviate a 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 problemi di prestazioni e conflitti in IIS insieme a ASP.NET, visitare i blog Microsoft seguenti: