Condividi tramite


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 il maxIoThreads 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 il minLocalRequestFreeThreads parametro su 76*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 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: