8
votes

Alternatives à l'état de la session HTTP dans l'application Web Plain-vanilla .NET Web Services

Après une longue lutte avec le cycle de vie de la page dans ASP.NET et ses performances, nous avons commencé à refactore notre application Web pour mettre en œuvre des services Web (web-Web-WebLX .NASMX .NAMX .NAMX .NASMX) et jQuery sur le côté client . Remarque: cela ne met pas en œuvre MVC ou ASP.NET de quelque manière que ce soit, ce sont des services Web.

Dans les deux dispensations de l'application, nous génèverons tout le contenu de manière dynamique dans une seule page. Dans la dispensation ASP.NET, cela signifiait (due au cycle de vie de la page) que toute la page devait être déchirée et reconstruite avec (presque) tous les ajax ou modifier le formulaire Web. Cela a présenté un énorme problème d'évolutivité pour une application destinée à desservir de nombreux utilisateurs concurrents. Dans la dispensation des services Web / JQuery, nous pouvons vous concentrer sélectivement sur uniquement les éléments du DOM qui doivent envoyer ou recevoir des données sur le serveur, ce qui signifie beaucoup moins de demandes et une expérience utilisateur beaucoup plus rapide.

La première itération de l'application a montré une amélioration de la performance par un ordre de grandeur; Cependant, comme nous avons commencé à créer de plus en plus de services Web, la performance de l'application est maintenant à la parité avec la performance de la dispensation ASP.NET.

Après de nombreuses recherches de googling / âme et des tests de charge, il est devenu évident que la session HTTP était le coupable. Essentiellement, chaque lecture (et parfois en incluant simplement une session dans la méthode de la méthode de service Web) est un appel de blocage qui introduit un délai de 500 ms. Une fois que vous savez où regarder, cela est bien documenté dans la littérature MSDN. Comme implémenté, Session (si utilisé par plusieurs services Web par le même utilisateur) transforme les demandes asynchrones dans des demandes synchrones avec un tampon de 500 ms. Nous l'atténuons actuellement en enchaînant tous nos appels Ajax comme des événements "sur le succès" les uns des autres, ce qui en fait des demandes synchrones du côté du client. Cela élimine le délai de 500 ms engagé en demandant une lecture sur un objet de session verrouillée.

Faire le comportement de l'application côté client d'une manière "synchrone" a résolu de nombreux problèmes de performance; Cependant, ce n'est qu'une solution d'arrêt à court terme.

Quelles alternatives viables (évolutives!) à la session existent, gardant à nouveau à l'esprit que nous ne sommes pas sur ASP.NET ou MVC ou WCF, etc.? Notre plus grand obstacle est la persistance de notre collection de métadonnées initialisée pour chaque utilisateur sur la connexion. C'est la seule opération la plus chère de l'application (par un facteur de 10 ou plus), et celle que nous voulons seulement exécuter une fois. La session a fourni un moyen simple de transpirer à l'ancienne une fois et ne jamais regarder en arrière; Mais cette approche semble moins réalisable.

Une approche peut être d'éliminer cette classe de dieu de la collection de métadonnées unique et d'évoluer cette classe monothéiste dans une collection polythéiste de Demigodes. L'instancitation Les Demigodes pourraient être effectués plus fréquemment à moindre coût. Faisable mais nécessite un refactoring considérable, un développement étendu et une période de QA. Un autre candidat stocke simplement toutes les informations de l'état dans la base de données, mais cela a ses propres coûts - la latence n'est pas la moindre dont.

Y a-t-il d'autres solutions à ce problème qui pourraient impliquer un niveau d'effort inférieur à mettre en œuvre?


3 commentaires

Par curiosité, pourquoi n'utilisez-vous pas WCF? Il peut produire exactement le même type de service, au profit de l'utilisation de la technologie héritée.


Juste une aversion pour la négociation de l'avantages / inconvénients relativement compréhensifs d'une solution Microsoft Box Noir pour le pros / Infers inconnu d'une autre solution Microsoft. Si vous faites tout ce que Microsoft entend, vous ne rencontrez pas ces problèmes. Mais lorsque vous essayez de faire sortir leur technologie de la boîte, des problèmes surviennent. Nous avons été gravés à quelques reprises par cela. WCF résoudra-t-il vraiment le problème sans injecter ses propres "idiosyncrasies"?


N'hésitez pas à utiliser des technologies obsolètes si vous le souhaitez, mais ils finissent par cesser d'être pris en charge. Il n'y aura jamais une autre nouvelle fonctionnalité dans les services ASMX et il y aura très peu de corrections de bugs, soit. WCF est environ 1000 fois mieux que les services Web ASMX, mais peuvent être à peu près aussi simples à utiliser. WCF est sorti depuis cinq ans. Peut-être que le temps de démarrer ou d'autre reste loin derrière.


4 Réponses :


1
votes

lancer plus de matériel!

Non, sérieusement. Pour les sites comme la vôtre, vous pourriez bénéficier de la configuration d'une machine distincte en tant que serveur d'état de session (voir documentation MSDN ), que vous pouvez faire à partir de l'interface graphique IIS ou de la ligne de commande.

Après avoir défini le serveur d'état, vous devez configurer votre Web config pour utiliser la nouvelle machine. Une belle description du processus est disponible ici , mais en bref, vous définissez le système web.config.web.SessionState de Web.web.Session comme suit: xxx

maintenant si Vous souhaitez y aller très lourd, vous pouvez avoir de nombreux serveurs d'état et écrire votre propre routine pour résoudre le serveur contenant votre état de session. Voir une description du processus ici . Cette stratégie devrait vous aider à augmenter plus ou moins indéfiniment sans abandonner votre utilisation de HTTPSession.


1 commentaires

Stocker les sessions sur un serveur séparé ne contribuera pas à résoudre le problème de la concurrence de la session. ASP.NET verrouillez toujours les demandes nécessitant un accès à la session et les exécutera en série.



0
votes

Sans voir votre code, ni ce que vous chargez et stockez en session, il est difficile de vous aider. Cependant, un deuxième délai de 35 ans pour la session n'est certainement pas normal dans mon expérience. J'aimerais beaucoup voir la documentation que vous parlez de cela dit que c'est le cas.

ASP.NET bien écrit (si WebForms, ASMX, MVC ou d'autres options) est certainement très évolutif.

qui étant dit, où votre session est-elle stockée? En cours? Le serveur d'état IIS? Dans un dB? Combien de données stockez-vous vraiment en session? Utilisez-vous vraiment toutes ces données que vous chargez en session presque toutes les demandes?

Il est difficile de vous donner une vraie réponse, sans mieux comprendre votre domaine de problème: ce que vous devez garder l'état pour, quelle est la taille des objets que vous utilisez pour garder l'état, la quantité de trafic que vous avez, etc.


6 commentaires

ASP.NET Apps avec des sessions, quelle que soit la qualité de l'écriture, ne sont pas du tout évolutives lorsque vous avez plusieurs demandes d'un seul client. ASP.NET est évolutif pour serveur de nombreux clients, mais lorsque des sessions sont impliquées, on synchronise les demandes de clients individuels afin de pouvoir exécuter une séquence.


La session induit en effet des problèmes d'évolutivité pour cette raison. Cependant, et peut-être auriez-moi dû être plus direct, l'affiche pourrait être mieux à l'étude de la manière dont la session est utilisée. "Un appel de blocage qui introduit un retard de 500 ms" est un enfer de beaucoup de temps. La plupart des navigateurs ne limitent pas les demandes d'ASYNCH à 2 appels simultanés par défaut? Combien de demandes sont faites simultanément pour le causer, ou de la quantité de modification de l'Etat et de la taille de cet état, surtout si c'est dans Proc !?


@Chad Ruppert, la limite d'appel 2 était il y a longtemps, mais est techniquement toujours dans la spécification HTTP. Seulement IE6, je pense toujours adhérer à cette limite. 8 est beaucoup plus fréquent avec les navigateurs modernes (y compris IE8 / 9).


@Samuel Neff et les navigateurs mobiles aussi? :) La codage à la spécification est toujours en sécurité. Snarkiness Mister, merci d'avoir souligné que l'augmentation des connexions par défaut ... Personnellement, je ne me souviens que de la dernière fois que j'utilisais réellement la session dans une application pour l'État et suggérerait toujours que c'est probablement une violation probable de la session dans cette cas et pourrait probablement être refactored. (dit sans comprendre ce que fait l'affiche)


Dans ce contexte, la session est dans Proc. Pour clarifier, le délai de 500 ms semble être injecté par le processus de travailleur de l'IIS. Une fois que la session est "verrouillée", un appel simultané attendra immédiatement une demi-seconde avant de tenter à nouveau. Cela ne semble pas être configurable sur le côté IIS. Ce comportement n'est dans aucune documentation que j'ai trouvée; Cependant, le profilage de l'application dans Fiddler montre ce résultat à chaque fois. Les clients sont limités à 6 demandes simultanées. Je peux voir chaque demande simultanée dans le bloc de 6 inciter ce délai de 500 ms.


@Christopher tu écris à la session avec tous ces appels ou juste en train de lire? L'état pourrait-il avoir besoin d'être atteint d'une autre manière? Est-ce que toutes ces informations sont si critiques et que vous avez besoin de sécurité et de logique sur le serveur que vous ne pouviez pas stocker l'état pour certains de ses clients?



1
votes

Si la plupart de vos demandes n'ont besoin que de lire-accès à la session, vous avez une solution simple. Définissez le EnableSessionState Attribut à Readonly et ils acquièrent une serrure en lecture seule sur la session uniquement. Je ne sais pas comment appliquer cela aux servieurs Web, mais je suis sûr qu'il y a un cadre équivalent.

http://msdn.microsoft.com/en-us/ Bibliothèque / AA479041.aspx # AspnetsSessionState_topic3 ​​

Autre que cela, ASP.NET verrouille l'objet de session pour toute la durée de chaque demande et sérialise efficacement les demandes. Une solution pour permettre aux demandes d'exécution en parallèle n'est pas utilise les sessions intégrées et roulez votre propre solution. L'avantage ici est que vous pouvez utiliser beaucoup plus fin de verrouillage grainé de sorte que certains aspects des demandes devront être synchronisés et seront exécutés en série, mais la majorité de chaque demande peut fonctionner en parallèle.

Une solution alternative consiste simplement à réduire le nombre d'appels parallèles par demande. N'essayez pas de les exécuter en parallèle du tout. Lottrez-les sur son côté client et envoyez-leur comme une seule demande. Vous vous retrouverez avec moins de frais généraux dans le nombre de demandes, moins de chances d'un seul client qui collecte beaucoup de ressources, et très probablement obtenir une meilleure performance globale et pour chaque demande agrégée.


2 commentaires

Réduire le nombre d'appels parallèles par demande est une bonne idée; Cependant, cela peut devenir difficile à gérer. Si le client dispose de 10 appels de service Web communs pour faire, mais peut en faire un nombre, dans n'importe quel ordre, il peut être difficile de l'assembler dans une seule demande côté client et plus difficile à configurer un service Web à traiter cette demande arbitraire de manière à interpréter le client. Bien sûr, si vous pouviez transmettre une fonction d'objet de première classe équivalente à partir de JavaScript à un service Web .NET, ce serait un cheval de couleur différente.


@Christopher, Yup, ce n'est pas un changement facile. Cela ne doit pas être à 100%. Utilisez la journalisation ou un proxy de débogage comme Charles ou violondler pour identifier les pires délinquants et simplement résoudre ceux-ci.



1
votes

C'est vraiment facile de résoudre votre problème.

  1. désactiver la session dans votre web.config pour l'ensemble du site Web
  2. Créez une table dans SQL Server:

    Créer une session de table ( SessionID Int (ou un GUID) ... ... )

  3. Créez des tables séparées qui ont une clé étrangère à votre table de session (avec Supprimer CASCADE) et que les informations spécifiques de la session de magasin

  4. du côté de l'application, stockez la sessionID dans un cookie ou dans la chaîne de requête. Vous pouvez ensuite rechercher toutes les informations de session dont vous avez besoin à la demande. Cela fonctionnera beaucoup plus rapidement que les fournisseurs d'états de session par défaut, car vous n'avez que des informations lorsque vous avez besoin de l'information! De plus, vous n'avez plus besoin d'emporter l'objet de session par défaut sur votre dos plus longtemps.


2 commentaires

C'est le chemin que nous sommes descendus. Nous avons désactivé la session HTTP complètement et stocké toutes les données persistantes dans la base de données. Il y a un coût de performance pour le faire (jusqu'à 250 ms sur de nombreuses demandes), mais nous n'avons plus d'appels de blocage - toutes les demandes sont traitées simultanément. Une optimisation supplémentaire est nécessaire, mais c'est la seule solution complète au problème.


Bon d'entendre. Une bonne chose à propos de cette approche est si vous passez à une technologie différente comme Silverlight ou même Java ou autre, vous pourrez continuer à utiliser cela pour une information de session persistante.