Problèmes de performances lorsque vous effectuez des appels à des services web à partir d’une application ASP.NET

Cet article fournit une aide pour résoudre les problèmes de performances qui se produisent lorsque vous effectuez des appels à des services web à partir d’une application Microsoft ASP.NET.

              Version d’origine du produit : ASP.NET
Numéro de la base de connaissances d’origine : 821268

Symptômes

Lorsque vous effectuez des appels à des services web à partir d’une application ASP.NET, vous pouvez rencontrer des conflits, des performances médiocres et des interblocages. Les clients peuvent signaler que les demandes cessent de répondre ou prennent beaucoup de temps à s’exécuter. En cas de suspicion d’interblocage, le processus de travail peut être recyclé.

Vous pouvez recevoir le message d’erreur d’exception suivant lorsque vous effectuez un appel à la HttpWebRequest.GetResponse méthode :

« System.InvalidOperationException : il n’y avait pas assez de threads libres dans l’objet ThreadPool pour terminer l’opération. »

Vous pouvez également recevoir le message d’erreur d’exception suivant dans le navigateur :

« HttpException (0x80004005) : la demande a expiré. »

Remarque

Cet article s’applique également aux applications qui effectuent directement des HttpWebRequest demandes.

Cause

Ce problème peut se produire car ASP.NET limite le nombre de threads de travail et de ports de saisie semi-automatique qu’un appel peut utiliser pour exécuter des demandes.

En règle générale, un appel à un service web utilise un thread de travail pour exécuter le code qui envoie la requête et un thread de port de saisie semi-automatique pour recevoir le rappel du service web. Toutefois, si la requête est redirigée ou nécessite une authentification, l’appel peut utiliser jusqu’à deux threads de travail et deux threads de port de saisie semi-automatique. Par conséquent, vous pouvez épuiser le managé ThreadPool lorsque plusieurs appels de service web se produisent en même temps.

Par exemple, supposons que le ThreadPool est limité à 10 threads de travail et que les 10 threads de travail exécutent actuellement du code qui attend qu’un rappel s’exécute. Le rappel ne peut jamais s’exécuter, car tous les éléments de travail qui sont mis en file d’attente vers le ThreadPool sont bloqués jusqu’à ce qu’un thread soit disponible.

Une autre source potentielle de conflit est le maxconnection paramètre que l’espace System.Net de noms utilise pour limiter le nombre de connexions. En règle générale, cette limite fonctionne comme prévu. Toutefois, si de nombreuses applications essaient d’effectuer plusieurs requêtes à une seule adresse IP en même temps, les threads peuvent avoir à attendre une connexion disponible.

Résolution

Pour résoudre ces problèmes, vous pouvez paramétrer les paramètres suivants dans le fichier Machine.config en fonction de votre situation :

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

Pour résoudre ces problèmes, effectuez les actions suivantes :

  • Limitez le nombre de requêtes ASP.NET qui peuvent s’exécuter en même temps à environ 12 par processeur.
  • Autoriser les rappels de service web à utiliser librement des threads dans le ThreadPool.
  • Sélectionnez une valeur appropriée pour le maxconnections paramètre . Basez votre sélection sur le nombre d’adresses IP et de domaines d’application utilisés.

Remarque

La recommandation de limiter le nombre de demandes de ASP.NET à 12 par processeur est un peu arbitraire. Toutefois, cette limite s’est avérée efficace pour la plupart des applications.

MaxWorkerThreads et maxIoThreads

ASP.NET utilise les deux paramètres de configuration suivants pour limiter le nombre maximal de threads de travail et de threads de saisie semi-automatique utilisés :

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

Le maxWorkerThreads paramètre et le maxIoThreads paramètre sont implicitement multipliés par le nombre de processeurs. Par exemple, si vous avez deux processeurs, le nombre maximal de threads de travail est de 2 * maxWorkerThreads.

MinFreeThreads et minLocalRequestFreeThreads

ASP.NET contient également les paramètres de configuration suivants qui déterminent le nombre de threads de travail et de ports d’achèvement qui doivent être disponibles pour démarrer une demande distante ou une demande locale :

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

S’il n’y a pas suffisamment de threads disponibles, la demande est mise en file d’attente jusqu’à ce que suffisamment de threads soient libres d’effectuer la requête. Par conséquent, ASP.NET n’exécutez pas plus que le nombre de requêtes suivant en même temps :

(maxWorkerThreads * nombre d’uc) - minFreeThreads

Remarque

Le minFreeThreads paramètre et le minLocalRequestFreeThreads paramètre ne sont pas implicitement multipliés par le nombre de processeurs.

MinWorkerThreads

ASP.NET contient également le paramètre de configuration suivant qui détermine le nombre de threads de travail qui peuvent être mis à disposition immédiatement pour traiter une demande distante.

<processModel minWorkerThreads="1">

Les threads contrôlés par ce paramètre peuvent être créés beaucoup plus rapidement que les threads de travail créés à partir des fonctionnalités de réglage des threads par défaut du Common Language Runtime (CLR).

Ce paramètre permet ASP.NET de traiter les demandes qui peuvent soudainement remplir la file d’attente des demandes ASP.NET en raison d’un ralentissement sur un serveur principal, d’une rafale soudaine de requêtes de l’extrémité du client ou d’un problème similaire qui entraînerait une augmentation soudaine du nombre de demandes dans la file d’attente.

La valeur par défaut du minWorkerThreads paramètre est 1. Nous vous recommandons de définir la valeur du minWorkerThreads paramètre sur la valeur suivante :

minWorkerThreads = maxWorkerThreads / 2

Par défaut, le minWorkerThreads paramètre n’est présent ni dans le fichier Web.config ni dans le fichier Machine.config . Ce paramètre est implicitement multiplié par le nombre d’uc.

Maxconnection

Le maxconnection paramètre détermine le nombre de connexions qui peuvent être établies à une adresse IP spécifique. Le paramètre apparaît comme suit :

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

Si le code de l’application fait référence à l’application par nom d’hôte au lieu de l’adresse IP, le paramètre doit apparaître comme suit :

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

Enfin, si l’application est hébergée sur un port autre que 80, le paramètre doit inclure le port non standard dans l’URL, comme ci-dessous :

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

Les paramètres des paramètres décrits plus haut dans cet article sont tous au niveau du processus. Toutefois, le paramètre s’applique maxconnection au niveau AppDomain. Par défaut, étant donné que ce paramètre s’applique au niveau AppDomain, vous pouvez créer un maximum de deux connexions à une adresse IP spécifique à partir de chaque AppDomain dans votre processus.

ExecutionTimeout

ASP.NET utilise le paramètre de configuration suivant pour limiter le temps d’exécution de la requête :

<httpRuntime executionTimeout="90"/>

Vous pouvez également définir cette limite à l’aide de la Server.ScriptTimeout propriété .

Remarque

Si vous augmentez la valeur du executionTimeout paramètre, vous devrez peut-être également modifier le processModelresponseDeadlockInterval paramètre.

Recommandations

Les paramètres recommandés dans cette section peuvent ne pas fonctionner pour toutes les applications. Toutefois, les informations supplémentaires suivantes peuvent vous aider à effectuer les ajustements appropriés.

Si vous effectuez un appel de service web à une seule adresse IP à partir de chaque page ASPX, Microsoft vous recommande d’utiliser les paramètres de configuration suivants :

  • Définissez les valeurs du maxWorkerThreads paramètre et du maxIoThreads paramètre sur 100.
  • Définissez la valeur du paramètre sur maxconnection12*N (où N est le nombre de processeurs dont vous disposez).
  • Définissez les valeurs du paramètre sur minFreeThreads88*N et le minLocalRequestFreeThreads paramètre sur 76*N.
  • Définissez la valeur de minWorkerThreads sur 50. N’oubliez pas que minWorkerThreads n’est pas dans le fichier de configuration par défaut. Vous devez l’ajouter.

Certaines de ces recommandations impliquent une formule simple qui implique le nombre de processeurs sur un serveur. La variable qui représente le nombre d’UC dans les formules est N.

Pour ces paramètres, si l’hyperthreading est activé, vous devez utiliser le nombre d’uc logiques au lieu du nombre de processeurs physiques. Par exemple, si vous avez un serveur à quatre processeurs avec l’hyperthreading activé, la valeur de N dans les formules est 8 au lieu de 4.

Remarque

Lorsque vous utilisez cette configuration, vous pouvez exécuter un maximum de 12 requêtes ASP.NET par processeur en même temps, car 100-88=12. Par conséquent, au moins 88*N threads de travail et 88*N threads de port de saisie semi-automatique sont disponibles pour d’autres utilisations (par exemple, pour les rappels de service web).

Par exemple, vous disposez d’un serveur avec quatre processeurs et l’hyperthreading activé. En fonction de ces formules, vous devez utiliser les valeurs suivantes pour les paramètres de configuration mentionnés dans cet article.

<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>

En outre, lorsque vous utilisez cette configuration, 12 connexions sont disponibles par uc et adresse IP pour chaque AppDomain. Par conséquent, dans le scénario suivant, très peu de contention se produit lorsque les requêtes attendent des connexions et que le ThreadPool n’est pas épuisé :

  • Le web héberge une seule application (AppDomain).
  • Chaque demande pour une page ASPX effectue une demande de service web.
  • Toutes les demandes sont adressées à la même adresse IP.

Toutefois, lorsque vous utilisez cette configuration, les scénarios qui impliquent l’une des connexions ci-dessous utilisent probablement trop de connexions :

  • Les demandes concernent plusieurs adresses IP.
  • Les requêtes sont redirigées (code 302 status).
  • Les demandes nécessitent une authentification.
  • Les requêtes sont effectuées à partir de plusieurs AppDomains.

Dans ces scénarios, il est judicieux d’utiliser une valeur inférieure pour le maxconnection paramètre et des valeurs supérieures pour le minFreeThreads paramètre et le minLocalRequestFreeThreads paramètre.

Plus d’informations

Pour plus d’informations, consultez Amélioration des performances ASP.NET.

Si vous rencontrez des performances et des conflits médiocres sur IIS avec ASP.NET, consultez les blogs Microsoft suivants :