9
votes

SortieCache ASP.NET (MVC) et demandes simultanées

Disons que, issuellement, j'ai une action de page / contrôleur sur mon site Web qui fait des choses très lourdes. Il faut environ 10 secondes pour terminer son fonctionnement.

Maintenant, j'utilise le mécanisme de sortie de la sortie .NET pour le mettre en cache pendant 15 minutes (à examiner, j'utilise [sortieCache (Durée = 900)] ) Que se passe-t-il si, après 15 minutes, le cache est expiré et 100 utilisateurs demandent à nouveau la page dans les 10 secondes qu'il faut pour faire le traitement lourd?

  1. Le matériel lourd ne fait que la première fois, et il y a un mécanisme de verrouillage de manière à ce que les autres autres utilisateurs obtiennent le résultat du cache
  2. Le matériel lourd est fait à 100 reprises (et le serveur est érafonné car il peut prendre jusqu'à 100 * 10 secondes)

    Question facile peut-être, mais je ne suis pas sûr à 100%. J'espère que c'est le numéro un, cependant: -)

    Merci!


0 commentaires

5 Réponses :


4
votes

Eh bien, cela dépend de la manière dont vous avez configuré IIS. Si vous avez moins de 100 threads ouvrières (disons, 50), alors le «truc lourde» est fait 50 fois, carabitez votre serveur, puis les 50 demandes restantes seront desservies dans le cache.

mais non, il n'y a pas de "mécanisme de verrouillage" sur un résultat de l'action en cache; ce serait contre-productif, pour la plupart.

EDIT : Je crois que cela sera vrai, mais les tests de Nick en disent le contraire, et je n'ai pas le temps de tester maintenant. Essayez-le vous-même! Le reste de la réponse n'est pas dépendant de ce qui précède, cependant, et je pense que c'est plus important.

En règle générale, toutefois, aucune demande de bande, mise en cache ou non, devrait prendre 10 secondes pour revenir. Si j'étais à votre place, je regarderais en quelque sorte préconiser la partie difficile de la demande. Vous pouvez toujours mettre en cache le résultat d'action si vous souhaitez mettre en cache le HTML, mais cela ressemble à votre problème est quelque peu plus gros que cela.

vous pourrait souhaitez aussi Considérons les contrôleurs asynchrones . Enfin, notez que bien que IIS et ASP.NET MVC ne verrouillent pas ce lourd calcul, vous pourriez. Si vous utilisez des contrôleurs asynchrones combinés à une serrure sur le calcul, vous obtiendrez effectivement le comportement que vous demandez. Je ne peux pas vraiment dire si c'est la meilleure solution sans en savoir plus sur ce que vous faites.


2 commentaires

Merci Heavens Je n'ai vraiment pas de demande qui prend 10 secondes, mais j'ai grandement exagéré d'illustrer un point. J'étais juste curieux ce qui se passerait dans un tel scénario. Merci! Pourrait envisager de mettre en œuvre des contrôleurs asynchronisés cependant.


Était un moment ... juste fait un test moi-même et je suis sûr qu'il ne se verrouille pas, comme vous l'avez dit. Merci.



3
votes

Il semble verrouiller ici, faire un test simple:

<asp:Literal ID="litCount" runat="server" />

public static int Count = 0;

protected void Page_Load(object sender, EventArgs e)
{
  litCount.Text = Count++.ToString();
  System.Threading.Thread.Sleep(10000);
}


10 commentaires

Testez-vous sur webdev? Il se comporte très différemment que IIS sur un serveur multi-core.


@CRAIG: Test à l'aide de IIS 7.5, Windows 7 x64 sur un quad-core


Cela semble étrange. Peut-être que vous utilisez le mode de débogage? Ce vraiment ne devrait pas verrouiller. Les autres demandes devraient avoir une erreur de cache.


@CRAIG: Nope, mode de sortie ... Juste attacher le débogueur dans IIS, mais bien sûr, il est possible que cela affecte le comportement. De l'autre côté, ce serait le comportement optimal, car IIS d'avoir d'autres demandes d'attente et que tout résulte du premier coup de traitement. Si vous spécifiez le cache de sortie, vous dites une sorte de dire que vous ne voulez pas que cette chose traite souvent et que IIS agisse de cette manière, cela aurait accompli et servirait toujours toutes les demandes le plus rapidement possible (le thread de la première requête devrait en premier lieu. , dans la plupart des cas).


Si la demande est toujours en cours, il n'est pas du tout évident que la demande suivante sera un cache frappé même si la première demande complète. Je suggérerais de tester avec une journalisation plutôt que du débogueur.


@CRAIG: Pouvez-vous expliquer un peu plus ce que vous voulez dire? Si un utilisateur effectue une demande n ° 2 qui toucherait la même sortie (comme dans les allumettes de Varbywhatever), il ne faut pas attendre la demande de remplir et de retourner ce résultat à tous ceux qui auraient frappé le cache avaient-ils frappé la même chose Moments plus tard? Cela devrait être le même résultat. (Si ce n'est pas le cas, vous ne devriez pas utiliser SortieCache) Si cela ne l'a pas fait et que vous avez obtenu 1000 hits à la fois, vous traiteriez le même résultat 1000 fois, au lieu d'une fois rapidement et revenez à 1000 demandes .. .Makes Sense que cela se comporterait de cette façon.


Le cache peut avoir une dépendance. Il peut également être effacé par un autre code.


@CRAIG, c'est un point équitable, mais ils demanderaient tous la page telle qu'elle était à l'instant, ils sont tous allés pour cela, peut-être encore. J'ai essayé un test similaire comme vous l'avez demandé ici, le mode de sortie, aucun débogage avec un Int statique qui est incrémenté chaque processus de page ... le même résultat, le nombre seulement est heurté une fois. Je vais mettre à jour la réponse pour montrer cette approche.


Je crois que quelque chose n'est pas juste ici, mais je n'ai pas le temps de le traverser moi-même. Donc +1 pour tester, et je vais mettre à jour ma réponse pour refléter ce que vous avez fait.


@CRAIG: J'apprécie la discussion intelligente. S'il vous plaît faire des tests ... comme je vais utiliser cela dans un proche avenir, je serais très curieux si vous obtenez un comportement différent.



1
votes

J'ai fait un petit test qui pourrait aider. Je crois ce que j'ai découvert, c'est que les demandes non accompagnées ne bloquent pas, et chaque demande qui entre dans le cache est expirée et avant que la tâche soit terminée, déclenche également cette tâche.

Par exemple, le code ci-dessous prend environ 6 -9 secondes sur mon système en utilisant Cassini. Si vous envoyez deux demandes, à environ 2 secondes (c'est-à-dire deux onglets de navigateur), les deux recevront des résultats uniques. La dernière demande de finition est également la réponse mise en cache pour les demandes suivantes. P>

// CachedController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HttpCacheTest.Controllers
{
    public class CachedController : Controller
    {
        //
        // GET: /Cached/

        [OutputCache(Duration=20, VaryByParam="*")]
        public ActionResult Index()
        {
            var start = DateTime.Now;

            var i = Int32.MaxValue;
            while (i > 0)
            {
                i--;
            }
            var end = DateTime.Now;

            return Content( end.Subtract(start).ToString() );
        }

    }
}


0 commentaires

3
votes

Une ancienne question, mais j'ai couri dans ce problème et j'ai fait une enquête.

Exemple code: xxx

exécutez-le dans un navigateur et il semble que cela semble Verrouiller et attendre.

exécutez-le dans différents navigateurs (j'ai testé dans IE et Firefox) et les demandes ne sont pas activées.

de sorte que le comportement "correct" a plus à voir avec quel navigateur vous Utilisez que la fonction dans IIS.

Edit: pour clarifier - pas de verrouillage. Le serveur est frappé par toutes les demandes qui parviennent à entrer avant que le premier résultat ne soit mis en cache, éventuellement entraînant un coup dur sur le serveur pour des demandes lourdes. (Ou si vous appelez un système externe, ce système pourrait être amené si votre serveur sert de nombreuses demandes ...)


0 commentaires

0
votes

Vous devez vérifier ces informations ici : "Vous avez un seul client qui apporte plusieurs demandes simultanées au serveur. Le comportement par défaut est que ces demandes seront sérialisées;"

Donc, si la demande simultanée du client unique est sérialisée, la demande suivante utilisera le cache. Cela explique que certains comportements semblent dans certaines réponses ci-dessus (@ Mats-Nilsson et @ Nick-Craver)

Le contexte que vous avez montré est plusieurs utilisateurs, qui vous appuieront votre serveur en même temps et que votre serveur sera occupé jusqu'à ce que vous puissiez terminer au moins une requête et créé le cache de sortie et l'utiliser pour la prochaine demande. Donc, si vous souhaitez sérialiser plusieurs utilisateurs demandant la même ressource, nous devons comprendre comment fonctionne la demande sérialisée pour un seul utilisateur. Est-ce ce que vous voulez?


0 commentaires