Auteur : Rob Howard Traduction : Poissons tropicaux
Cet article traite des sujets suivants :
· Secrets généraux de performances ASP.NET
· Conseils et astuces utiles pour améliorer les performances d'ASP.NET
· Recommandations pour l'utilisation des bases de données dans ASP.NET
· Mise en cache et traitement en arrière-plan dans ASP.NET
Écrire une application Web à l’aide d’ASP.NET est incroyablement simple. C'est si simple que de nombreux développeurs ne prennent pas le temps de créer leurs applications pour qu'elles fonctionnent correctement. Dans cet article, je recommande 10 conseils pour écrire des applications Web hautes performances. Je ne limiterai pas mon exposé aux applications ASP.NET, car les applications ASP.NET ne constituent qu'un sous-ensemble des applications Web. Cet article n'est pas destiné à être un guide définitif pour optimiser les performances des applications Web - un livre complet pourrait facilement le faire. Nous devrions plutôt considérer cet article comme un bon point de départ.
Avant de devenir un bourreau de travail, je faisais beaucoup d’escalade. Avant de faire une quelconque escalade, je préfère consulter les itinéraires dans un guide de voyage et lire les recommandations des personnes ayant visité le sommet. Mais peu importe la qualité d’un guide, vous avez besoin d’une véritable expérience de l’escalade avant de tenter un objectif ambitieux. De même, vous ne pouvez apprendre à écrire des applications Web hautes performances que lorsque vous devez résoudre des problèmes de performances ou exécuter un site à haut débit.
Mon expérience personnelle vient de mon travail en tant que gestionnaire de programme Foundation au sein de l'équipe ASP.NET chez Microsoft, de la maintenance et de la gestion de www.asp.net et de l'aide à l'architecture de Community Server, l'une des nombreuses applications ASP.NET bien connues (ASP.NET Forums , .Text et nGallery connectés à une seule plateforme). Je suis sûr que certains de ces conseils qui m'ont aidé vous seront également utiles.
Vous devriez envisager de séparer votre application en plusieurs couches logiques. Vous avez peut-être entendu parler d'une architecture à 3 niveaux (ou à n niveaux). Il s’agit généralement de modèles structurels prescrits qui divisent physiquement l’entreprise et/ou le matériel en divisions fonctionnelles. Si le système nécessite une plus grande échelle, davantage de matériel peut être facilement ajouté. Cependant, cela entraînera une dégradation des performances associée aux sauts d’activité et de machine, nous devons donc l’éviter. Ainsi, dans la mesure du possible, essayez d’exécuter la page ASP.NET et les composants associés à la page dans la même application.
En raison de la séparation du code et des limites entre les couches, l'utilisation de services Web ou de services à distance peut réduire les performances de 20 % ou plus.
La couche de données est un peu différente car il est généralement préférable d'avoir du matériel dédié à la base de données. Cependant, le coût du transfert du processus vers la base de données reste élevé, c'est pourquoi les performances de la couche de données doivent être votre première considération lors de l'optimisation de votre code.
Avant d'investir dans la résolution des problèmes de performances de votre application, assurez-vous d'analyser votre application pour découvrir la cause première du problème. Les compteurs de performances clés (tels que celui qui indique le pourcentage de temps passé à effectuer le garbage collection) sont également très utiles pour déterminer où l'application passe la majorité de son temps. Bien que les endroits où l'on passe du temps soient souvent moins intuitifs.
Dans cet article, j'aborde deux manières d'améliorer les performances : les optimisations à grande échelle, telles que l'utilisation de la mise en cache ASP.NET, et les optimisations à petite échelle, qui sont souvent répétées. Ces petites pièces d’optimisation sont parfois les plus intéressantes. Une petite modification que vous apportez à votre code sera appelée des milliers de fois. Optimisez les gros morceaux et vous constaterez peut-être une augmentation importante des performances globales. En optimisant par petites portions, vous pouvez gagner quelques microsecondes sur une requête donnée, mais de manière cumulative pour toutes les requêtes quotidiennes, vous obtiendrez une amélioration inattendue des performances.
Performances dans la couche de données
Lorsque vous commencez à optimiser les performances d'une application, il existe un test décisif que vous pouvez prioriser : le code doit-il accéder à une base de données ? Si oui, à quelle fréquence visitez-vous ? Notez que ce test peut également être appliqué au code qui utilise des services Web ou un contrôle à distance, mais je n'en parlerai pas dans cet article.
Si une requête de base de données est requise dans un certain chemin de code de votre code et que vous trouvez d'autres endroits où vous souhaitez prioriser les optimisations, telles que la manipulation de chaînes, arrêtez et effectuez d'abord les tests critiques. À moins que vous n'ayez à résoudre un très mauvais problème de performances, votre temps sera mieux utilisé pour optimiser le temps nécessaire à la connexion à la base de données, la quantité de données renvoyées et les opérations que vous effectuez vers et depuis la base de données.
Maintenant que j'ai couvert les informations en général, examinons 10 conseils pour aider votre application à mieux fonctionner. Je commencerai par ceux qui ont l'impact le plus évident sur l'amélioration des performances.
Astuce 1 : Renvoyer plusieurs jeux de résultats
Jetez un œil au code de votre base de données pour voir si vous disposez de chemins de requête qui accèdent à la base de données plus d’une fois. Chacun de ces allers-retours réduit le nombre de requêtes que votre application peut traiter par seconde. En renvoyant plusieurs jeux de résultats dans une seule requête de base de données, vous pouvez réduire le temps global consommé par la communication avec la base de données. Après avoir réduit le nombre de requêtes que votre serveur de base de données doit gérer, vous rendez également votre système plus évolutif.
Généralement, vous pouvez utiliser des instructions SQL dynamiques pour renvoyer plusieurs jeux de résultats. Je préfère utiliser des procédures stockées. On peut se demander si vous devez mettre une logique métier dans une procédure stockée, mais je pense que si la logique d'une procédure stockée peut limiter les données renvoyées (réduit la taille de l'ensemble de données, le temps passé sur la connexion réseau et élimine le besoin de filtrer les données de la couche logique), alors c'est une bonne chose.
À l’aide d’une instance SqlCommand et de sa méthode ExecuteReader pour générer une classe métier fortement typée, vous pouvez déplacer le pointeur du jeu de résultats vers l’avant en appelant NextResult. La figure 1 montre un exemple de session qui utilise une classe définie pour générer plusieurs ArrayLists. Renvoyer uniquement les données dont vous avez besoin à partir de la base de données réduira considérablement les demandes de mémoire sur votre serveur.
1// lire le premier jeu de résultats
2reader = command.ExecuteReader();
3
4// lire les données de cet ensemble de résultats
5while (lecteur.Read()) {
6 fournisseurs.Add(PopulateSupplierFromIDataReader(reader));
7}
8
9// lire le prochain ensemble de résultats
10reader.NextResult();
11
12// lire les données de ce deuxième ensemble de résultats
13while (lecteur.Read()) {
14 produits.Add(PopulateProductFromIDataReader(reader));
15}
16
17
Astuce 2 – Accès aux données paginées
Le DataGrid d'ASP.NET offre une grande fonctionnalité : la prise en charge de la pagination des données. Lorsque la pagination est configurée dans le DataGrid, un nombre spécifique de résultats sera affiché à la fois. De plus, une interface utilisateur de pagination permettant de naviguer entre les résultats est affichée au bas du DataGrid. L'interface utilisateur paginée vous permet de naviguer vers l'avant ou vers l'arrière dans les données affichées, affichant un nombre spécifique de résultats par page.
Mais il y a un petit problème. Lorsque vous utilisez DataGrid pour la pagination, toutes les données doivent être liées à la table. Par exemple, votre couche de données devra renvoyer toutes les données, puis le DataGrid devra remplir tous les enregistrements à afficher en fonction de la page actuelle. Si 100 000 enregistrements sont renvoyés lorsque vous utilisez la pagination DataGrid, 99 975 enregistrements seront supprimés par demande (en supposant que la capacité de chaque page est de 25 enregistrements). Lorsque le nombre d'enregistrements augmente, les performances de l'application sont grandement affectées car de plus en plus de données doivent être renvoyées à chaque requête.
Une façon d’écrire un meilleur code de pagination consiste à utiliser des procédures stockées. La figure 2 montre un exemple de procédure stockée qui pagine la table de données Orders dans la base de données Nothwind. Fondamentalement, tout ce que vous avez à faire ici est de transmettre l'index de la page et la capacité de la page. La base de données calcule les jeux de résultats appropriés et les renvoie.
1CRÉER UNE PROCÉDURE northwind_OrdersPaged
2(
3 @PageIndex entier,
4 @PageSize entier
5)
6AS
7DEBUT
8DÉCLARER @PageLowerBound int
9DÉCLARER @PageUpperBound int
10DÉCLARE @RowsToReturn int
11
12-- Définissez d’abord le nombre de lignes
13SET @RowsToReturn = @PageSize * (@PageIndex + 1)
14SET ROWCOUNT @RowsToReturn
15
16--Définir les limites de la page
17SET @PageLowerBound = @PageSize * @PageIndex
18SET @PageUpperBound = @PageLowerBound + @PageSize + 1
19
20-- Créer une table temporaire pour stocker les résultats sélectionnés
21CRÉER UNE TABLE #PageIndex
vingt-deux (
23 IndexId int IDENTITÉ (1, 1) NON NULLe,
24 ID de commande entier
25)
26
27--Insérer dans la table temporaire
28INSÉRER DANS #PageIndex (OrderID)
29SÉLECTIONNER
30 Numéro de commande
31DE
32 commandes
33COMMANDER PAR
34 ID de commande DESC
35
36--Renvoyer le nombre total
37SELECT COUNT(OrderID) FROM Commandes
38
39-- Retourner les résultats paginés
40SÉLECTIONNER
41 O.*
42DE
43 commandes O,
44 #PageIndexIndex des pages
45OÙ
46 O.OrderID = PageIndex.OrderID ET
47 PageIndex.IndexID > @PageLowerBound ET
48 PageIndex.IndexID < @PageUpperBound
49COMMANDER PAR
50 PageIndex.IndexID
51
52FIN
53
54
Pendant la période de service communautaire, nous avons écrit un contrôle de serveur de pagination pour effectuer cette pagination de données. Vous remarquerez que j'ai utilisé l'idée évoquée dans l'astuce 1 pour renvoyer deux ensembles de résultats à partir d'une procédure stockée : le nombre total d'enregistrements et les données demandées.
Le nombre total d'enregistrements renvoyés peut varier en fonction de la requête effectuée. Par exemple, une clause WHERE peut être utilisée pour contraindre les données renvoyées. Il faut connaître le nombre total d'enregistrements à retourner afin de calculer le nombre total de pages à afficher dans l'interface utilisateur paginée. Par exemple, s'il y a 1 000 000 d'enregistrements au total et qu'une clause WHERE est utilisée pour filtrer ces enregistrements sur 1 000 enregistrements, la logique de pagination doit connaître le nombre total d'enregistrements pour soumettre l'interface utilisateur de pagination de manière appropriée.
Astuce 3 – Regroupement de connexions
L'établissement d'une connexion TCP entre votre application Web et SQL Server peut être une opération coûteuse. Les développeurs de Microsoft utilisent le pooling de connexions depuis un certain temps, ce qui leur permet de réutiliser les connexions aux bases de données. Plutôt que d'établir une nouvelle connexion TCP pour chaque requête, une nouvelle connexion est établie uniquement lorsqu'il n'y a aucune connexion disponible dans le pool de connexions. Lorsque la connexion est fermée, elle est renvoyée au pool de connexions - elle maintient toujours la connexion à la base de données, plutôt que de détruire complètement la connexion TCP.
Bien sûr, vous devez faire attention aux fuites de connexions. Fermez toujours vos connexions lorsque vous avez fini de les utiliser. Je le répète : peu importe ce que l'on dit à propos du mécanisme de récupération de place de Microsoft .NET Framework, vous devez toujours appeler explicitement la méthode Close ou Dispose sur votre connexion lorsque vous en avez terminé. Ne faites pas confiance au Common Language Runtime (CLR) pour nettoyer et fermer votre connexion à une heure prédéterminée. Le CLR finira par détruire la classe et forcera la fermeture de la connexion, mais vous n'avez aucune garantie lorsque le mécanisme de récupération de place sur l'objet sera réellement exécuté.
Pour obtenir les meilleurs résultats en utilisant le pool de connexions, vous devez suivre quelques règles. Commencez par ouvrir une connexion, effectuez le travail, puis fermez la connexion. Ce n'est pas grave si vous devez (de préférence en appliquant le conseil 1) ouvrir et fermer la connexion plusieurs fois par requête, c'est bien mieux que de laisser la connexion ouverte et de la transmettre à plusieurs méthodes différentes. Deuxièmement, utilisez la même chaîne de connexion (et bien sûr le même ID de thread si vous utilisez l'authentification intégrée). Si vous n'utilisez pas la même chaîne de connexion, par exemple différentes chaînes de connexion personnalisées basées sur l'utilisateur connecté, vous n'obtiendrez pas la même valeur optimale que celle fournie par le pool de connexions. Et si vous utilisez l’authentification intégrée lorsque vous usurpez l’identité d’un grand nombre d’utilisateurs, votre pool de connexions sera également beaucoup moins efficace. Les compteurs de performances des données .NET CLR peuvent être utiles lorsque vous essayez de détecter des problèmes de performances liés au regroupement de connexions.
Chaque fois que votre application se connecte à une ressource, telle qu'une base de données, ou s'exécute dans un autre processus, vous devez le faire en vous concentrant sur le temps nécessaire pour se connecter à la ressource, le temps nécessaire pour envoyer et recevoir des données, et le temps nécessaire à la connexion à la ressource. prend pour envoyer et recevoir des données. Il existe un certain nombre d'allers-retours vers la base de données à optimiser. L'optimisation de tout type de saut de processus dans votre application est la première étape pour commencer à obtenir de meilleures performances.
La couche application contient la logique qui se connecte à votre couche de données et transforme les données en instances de classe et processus logiques significatifs. Par exemple, dans un serveur de communauté, c'est ici que vous générez un forum ou une collection de fils de discussion et que vous appliquez des règles métier telles que les autorisations. Plus important encore, c'est ici que la logique de mise en cache est effectuée.
Astuce 4 – API de mise en mémoire tampon ASP.NET
La première chose à considérer avant de commencer à écrire la première ligne de code dans votre application est d'architecturer la couche application pour maximiser et tirer parti des fonctionnalités de mise en cache d'ASP.NET.
Si votre composant s'exécute dans une application ASP.NET, vous référencez simplement System.Web.dll dans votre projet d'application. Lorsque vous devez accéder au cache, utilisez la propriété HttpRuntime.Cache (cet objet est également accessible via Page.Cache et HttpContext.Cache).
Il existe plusieurs directives pour l'utilisation des données mises en cache. Premièrement, si les données peuvent être utilisées plusieurs fois, leur mise en cache est un bon choix. Deuxièmement, si les données sont générales et non spécifiques à une requête ou à un utilisateur spécifique, leur mise en cache est une excellente option. Si les données sont spécifiques à un utilisateur ou à une demande mais ont une longue durée de vie, elles peuvent être mises en cache mais ne peuvent pas être utilisées fréquemment. Troisièmement, un principe souvent négligé est que parfois vous pouvez trop mettre en cache. Généralement sur une machine x86, pour réduire le risque d'erreurs de mémoire insuffisante, vous souhaiterez exécuter un processus qui n'utilise pas plus de 800 Mo d'octets privés. La mise en cache doit donc être limitée. En d’autres termes, vous devrez peut-être réutiliser le résultat d’un calcul, mais si ce calcul nécessite dix paramètres, vous devrez peut-être essayer de mettre en cache 10 permutations, ce qui pourrait vous causer des ennuis. Les erreurs de mémoire insuffisante dues à la mise en cache excessive sont les plus courantes dans ASP.NET, en particulier avec les grands ensembles de données.
La mise en cache possède plusieurs fonctionnalités intéressantes que vous devez connaître. Premièrement, le cache implémente un algorithme utilisé le moins récemment, permettant à ASP.NET de forcer le vidage du cache (supprimant automatiquement les éléments inutilisés du cache) lorsque la mémoire fonctionne moins efficacement. Deuxièmement, le cache prend en charge les dépendances expirées qui peuvent être forcées à expirer. Ces dépendances incluent l'heure, les clés et les fichiers. Le temps est souvent utilisé, mais avec ASP.NET 2.0, un nouveau type d'invalidation plus puissant est introduit : l'invalidation du cache de base de données. Il s'agit de la suppression automatique des éléments du cache lorsque les données de la base de données changent. Pour plus d'informations sur l'invalidation du cache de base de données, consultez la colonne Dino Esposito Cutting Edge dans le numéro de juillet 2004 de MSDN Magazine. Pour comprendre l'architecture du cache, voir la figure 3.
Astuce 5 — Mise en cache par requête
Plus tôt dans cet article, j'ai mentionné que de petites améliorations des chemins de code fréquemment parcourus peuvent conduire à d'importants gains de performances globales. Parmi ces petites améliorations, l’une est définitivement ma préférée et je l’appelle la mise en cache par requête.
Les API de mise en cache sont conçues pour mettre en cache les données pendant une période plus longue ou jusqu'à ce que certaines conditions soient remplies, mais la mise en cache par requête signifie la mise en cache des données uniquement pendant la durée de cette requête. Pour chaque requête, un chemin de code spécifique est fréquemment consulté, mais les données ne sont extraites, appliquées, modifiées ou mises à jour qu'une seule fois. Cela semble un peu théorique, alors donnons un exemple concret.
Dans une application de forum de serveur communautaire, chaque contrôle serveur utilisé sur la page nécessite des données de personnalisation pour déterminer l'apparence à utiliser, la table de styles à utiliser et d'autres données de personnalisation. Certaines de ces données peuvent être mises en cache à long terme, mais certaines données ne sont récupérées qu'une seule fois par requête, puis réutilisées plusieurs fois au cours de cette requête, par exemple pour l'apparition d'un contrôle.
Pour réaliser la mise en cache par requête, utilisez ASP.NET HttpContext. Pour chaque requête, une instance HttpContext est créée et est accessible depuis n'importe où dans la propriété HttpContext.Current pendant la requête. La classe HttpContext possède une propriété de collection Items spéciale ; les objets et les données ajoutés à cette collection Items sont mis en cache uniquement pendant la durée de la requête. Tout comme vous pouvez utiliser la mise en cache pour stocker les données fréquemment consultées, vous pouvez également utiliser HttpContext.Items pour stocker des données qui ne sont utilisées que par requête. La logique derrière cela est très simple : les données sont ajoutées à la collection HttpContext.Items lorsqu'elles n'existent pas, et lors des recherches ultérieures, seules les données de HttpContext.Items sont renvoyées.
Astuce 6 — Traitement en arrière-plan
Le chemin vers le code doit être aussi rapide que possible, n'est-ce pas ? Il peut arriver que vous constatiez que vous effectuez une tâche très gourmande en ressources qui est effectuée à chaque demande ou toutes les n demandes. L’envoi d’e-mails ou l’analyse et la validation des données entrantes en sont quelques exemples.
En disséquant les forums ASP.NET 1.0 et en restructurant le contenu qui constitue le serveur de communauté, nous avons découvert que le chemin du code pour la publication de nouveaux messages était extrêmement lent. Chaque fois qu'un nouveau message est publié, l'application doit d'abord s'assurer qu'il n'y a pas de messages en double, puis elle doit analyser le message à l'aide d'un filtre "gros mots", analyser les émoticônes des personnages du message, marquer et indexer le message, et ajouter le publier à la demande lorsque cela est demandé. Ajoutez à la file d'attente appropriée, validez la pièce jointe et enfin envoyez une notification par e-mail à tous les abonnés immédiatement après la publication de la publication. De toute évidence, cela implique beaucoup de choses.
Après des recherches, il a été constaté que la plupart du temps était consacré à la logique d'indexation et à l'envoi d'e-mails. L'indexation des publications est une opération très fastidieuse et il a été découvert que la fonctionnalité intégrée System.Web.Mail se connecte à un serveur SMTP et envoie ensuite des e-mails en continu. À mesure que le nombre d'abonnés à une publication ou à un sujet particulier augmente, la fonction AddPost prend de plus en plus de temps à s'exécuter.
L'indexation des e-mails n'est pas requise pour chaque demande. Idéalement, nous aimerions regrouper cette opération, en indexant 25 publications à la fois ou en envoyant tous les e-mails toutes les cinq minutes. Nous avons décidé d'utiliser le code que j'avais utilisé pour prototyper l'invalidation du cache de données qui a finalement été incluse dans Visual Studio 2005.
La classe Timer dans l'espace de noms System.Threading est très utile, mais peu connue dans le .NET Framework, du moins parmi les développeurs Web. Une fois créée, cette classe Timer appellera le rappel spécifié à un intervalle configurable pour un thread dans le ThreadPool. Cela signifie que vous pouvez configurer votre code pour qu'il s'exécute sans requêtes entrantes vers l'application ASP.NET, ce qui est idéal pour le traitement en arrière-plan. Vous pouvez également effectuer des opérations telles que l'indexation ou l'envoi d'e-mails dans ce processus en arrière-plan.
Cependant, cette technologie pose plusieurs problèmes. Si le domaine d'application est désinstallé, cette instance de minuterie cessera de déclencher des événements. De plus, étant donné que le CLR a une norme stricte concernant le nombre de threads par processus, il peut arriver, sur un serveur très chargé, que le minuteur ne garantisse pas que les threads continuent de terminer l'opération et, dans une certaine mesure, puisse entraîner des retards. . ASP.NET tente de minimiser les risques que cela se produise en conservant un certain nombre de threads disponibles dans le processus et en n'utilisant qu'une partie du nombre total de threads pour le traitement des requêtes. Cependant, cela peut poser problème si vous effectuez de nombreuses opérations asynchrones.
Il n'y a pas assez de place ici pour ce code, mais vous pouvez télécharger un exemple facile à comprendre sur www.rob-howard.net . Découvrez les diapositives et les démos de la présentation Blackbelt TechEd 2004.
Astuce 7 — Mise en cache des sorties de page et serveurs proxy
ASP.NET est votre couche de présentation (ou devrait être votre couche de présentation) ; elle se compose de pages, de contrôles utilisateur, de contrôles serveur (HttpHandlers et HttpModules) et du contenu qu'ils génèrent. Si vous disposez d'une page ASP.NET qui génère une sortie (HTML, XML, images ou toute autre donnée) et que lorsque vous exécutez ce code à chaque requête, il génère la même sortie, vous disposez alors d'un outil qui peut être utilisé pour A excellente alternative à la mise en cache de sortie de page.
En ajoutant la ligne suivante en haut de la page :
<%@ Page OutputCache VaryByParams="aucun" Duration="60" %>
Vous pouvez effectivement générer une sortie pour cette page une fois, puis la réutiliser plusieurs fois pendant 60 secondes maximum, après quoi la page sera réexécutée et la sortie sera à nouveau ajoutée au cache ASP.NET. Ce comportement peut également être accompli à l'aide de certaines API programmables de bas niveau. Il existe plusieurs paramètres configurables pour la mise en cache des sorties, tels que la propriété VaryByParams que nous venons de mentionner. VaryByParams est simplement demandé, mais vous permet également de spécifier les paramètres HTTP GET ou HTTP POST pour modifier les entrées du cache. Par exemple, définissez simplement VaryByParam="Report" pour mettre en cache la sortie pour default.aspx?Report=1 ou default.aspx?Report=2. Des paramètres supplémentaires peuvent être spécifiés en spécifiant une liste séparée par des points-virgules.
Beaucoup de gens ne réalisent pas que lorsque la mise en cache de sortie est utilisée, les pages ASP.NET génèrent également des en-têtes HTTP qui sont transmis aux serveurs de mise en cache, tels que ceux utilisés par Microsoft Internet Security and Acceleration Server ou Akamai. Après avoir défini l'en-tête de la table de cache HTTP, les documents peuvent être mis en cache sur ces ressources réseau et les demandes des clients peuvent être satisfaites sans retourner au serveur d'origine.
Par conséquent, l’utilisation de la mise en cache de sortie de page ne rendra pas votre application plus efficace, mais elle peut réduire la charge sur le serveur car la technologie de mise en cache en aval met le document en cache. Bien sûr, il ne peut s'agir que de contenu anonyme ; une fois qu'il sera transmis, vous ne verrez plus jamais les demandes et vous ne pourrez plus effectuer d'authentification pour en empêcher l'accès.
Astuce 8 — Exécutez IIS 6.0 (même simplement pour utiliser le cache du noyau)
Si vous n'exécutez pas IIS 6.0 (Windows Server 2003), vous passerez à côté de certaines améliorations considérables des performances des serveurs Web Microsoft. Dans l’astuce 7, j’ai discuté de la mise en cache des sorties. Dans IIS 5.0, les requêtes passent par IIS puis dans ASP.NET. En ce qui concerne la mise en cache, le HttpModule dans ASP.NET reçoit la requête et renvoie le contenu du cache.
Si vous utilisez IIS 6.0, vous trouverez une petite fonctionnalité intéressante appelée cache du noyau qui ne nécessite aucune modification du code dans ASP.NET. Lorsqu'une demande de mise en cache de sortie est effectuée par ASP.NET, le cache du noyau IIS reçoit une copie des données mises en cache. Lorsqu'une requête provient d'un pilote réseau, le pilote au niveau du noyau (sans basculement de contexte en mode utilisateur) reçoit la requête, vide les données mises en cache dans la réponse si elles sont mises en cache, puis termine l'exécution. Cela signifie que lorsque vous utilisez la mise en cache en mode noyau avec la mise en cache de sortie IIS et ASP.NET, vous obtiendrez des résultats de performances incroyables. Lors du développement d'ASP.NET dans Visual Studio 2005, j'étais le responsable du développement responsable des performances d'ASP.NET. Les développeurs effectuent le travail spécifique, mais je peux voir tous les rapports qui se produisent chaque jour. Les résultats du cache en mode noyau sont toujours les plus intéressants. La caractéristique la plus courante est que le réseau est inondé de requêtes/réponses, alors qu'IIS ne fonctionne qu'à environ 5 % d'utilisation du processeur. C'est choquant ! Il existe bien sûr d'autres raisons d'utiliser IIS 6.0, mais la mise en cache en mode noyau est la plus évidente.
Astuce 9 — Utilisez la compression Gzip
Bien que l'utilisation de gzip ne soit pas nécessairement une astuce en matière de performances du serveur (car vous pouvez constater une augmentation de l'utilisation du processeur), l'utilisation de la compression gzip peut réduire le nombre d'octets envoyés par le serveur. Cela se traduit par une augmentation perçue de la vitesse des pages et une réduction de l'utilisation de la bande passante. En fonction des données envoyées, de leur degré de compressibilité et de la prise en charge ou non du navigateur client (IIS enverra uniquement le contenu compressé gzip aux clients prenant en charge la compression gzip, tels qu'Internet Explorer 6.0 et Firefox), votre serveur peut servir Plus demandes. En fait, presque chaque fois que vous réduisez la quantité de données renvoyées, vous augmentez le nombre de requêtes par seconde.
La compression Gzip est intégrée à IIS 6.0 et ses performances sont bien meilleures que la compression gzip utilisée dans IIS 5.0, ce qui est une bonne nouvelle. Malheureusement, lorsque vous essayez d'activer la compression gzip dans IIS 6.0, vous ne pourrez peut-être pas trouver le paramètre dans la boîte de dialogue Propriétés d'IIS. L'équipe IIS a intégré une excellente fonctionnalité gzip au serveur, mais a oublié d'inclure une interface utilisateur administrative pour l'activer. Pour activer la compression gzip, vous devez fouiller profondément dans les paramètres de configuration XML d'IIS 6.0 (afin de ne pas perdre le cœur). Soit dit en passant, le mérite revient à Scott Forsyth d'OrcsWeb pour m'avoir aidé à soulever ce problème avec le serveur www.asp.net hébergé sur OrcsWeb.
Cet article ne décrira pas les étapes. Veuillez lire l'article de Brad Wilson sur IIS6 Compression. Il existe également un article de la base de connaissances sur l'activation de la compression pour ASPX dans Activer la compression ASPX dans IIS. Notez toutefois qu'en raison de certains détails d'implémentation, la compression dynamique et la mise en cache du noyau ne peuvent pas exister simultanément dans IIS 6.0.
Astuce 10 — État d'affichage du contrôle du serveur
View State est un nom intéressant pour ASP.NET qui stocke certaines données d'état dans des champs de sortie cachés de la page générée. Lorsque la page est renvoyée au serveur, celui-ci peut analyser, valider et appliquer ces données d'état d'affichage à l'arborescence de contrôle de la page. Afficher l'état est une fonctionnalité très puissante car elle permet de conserver l'état avec le client et ne nécessite pas de cookies ni de mémoire serveur pour enregistrer cet état. De nombreux contrôles serveur ASP.NET utilisent l'état d'affichage pour conserver les paramètres créés lors des interactions avec des éléments de page, tels que l'enregistrement de la page actuelle affichée lors de la pagination des données.
Cependant, l’utilisation de l’état d’affichage présente également certains inconvénients. Premièrement, cela augmente la charge globale sur la page lorsqu’elle est servie ou demandée. Une surcharge supplémentaire se produit également lors de la sérialisation ou de la désérialisation des données d'état d'affichage renvoyées au serveur. Enfin, l'état d'affichage augmente l'allocation de mémoire sur le serveur.
Plusieurs contrôles serveur ont tendance à abuser de l’état d’affichage même lorsqu’il n’est pas nécessaire, le plus notable étant DataGrid. Le comportement par défaut de la propriété ViewState est activé, mais vous pouvez le désactiver au niveau du contrôle ou de la page si vous n'en avez pas besoin. Dans le contrôle, définissez simplement la propriété EnableViewState sur false ou définissez-la globalement sur la page à l'aide du paramètre suivant :
<%@ Page EnableViewState="false" %>
Si vous ne publiez pas la page ou ne régénérez pas toujours les contrôles de la page à chaque demande, vous devez désactiver l'état d'affichage au niveau de la page.
résumé
Je vous ai donné quelques conseils que je trouve utiles lors de l'écriture d'applications ASP.NET hautes performances. Comme je l'ai mentionné plus tôt dans cet article, il s'agit d'un guide préliminaire et non du dernier mot sur les performances d'ASP.NET. (Pour plus d'informations sur l'amélioration des performances des applications ASP.NET, consultez Amélioration des performances ASP.NET.) La meilleure façon de résoudre un problème de performances spécifique ne peut être trouvée que par votre propre expérience. Cependant, ces conseils devraient vous donner de bons conseils pour votre voyage. Dans le développement de logiciels, il existe peu d’absolus ; chaque application est unique.
Voir l'encadré « Mythes courants sur les performances ».
Rob Howard est le fondateur de Telligent Systems, spécialisé dans les applications Web hautes performances, la gestion de bases de connaissances et les systèmes de collaboration. Rob était auparavant employé par Microsoft, où il a contribué à la conception de l'infrastructure pour ASP.NET 1.0, 1.1 et 2.0. Pour contacter Rob, veuillez visiter [email protected] .
Lien d'origine : http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/default.aspx