2008-12-29 6 views
1

J'ai une exigence de créer un HttpHandler qui servira un fichier image (fichier statique simple) et aussi il va insérer un enregistrement dans la table SQL Server. (par exemple, http://site/some.img, où some.img est un HttpHandler) J'ai besoin d'un objet en mémoire (comme l'objet Generic List) auquel je peux ajouter des éléments sur chaque requête (je dois également prendre en compte quelques centaines ou milliers de requêtes par seconde) Je devrais être capable de décharger cet objet en mémoire dans la table sql en utilisant SqlBulkCopy.Besoin de suggestion pour la file d'attente en mémoire ASP.Net

Liste -> DataTable -> SqlBulkCopy

Je pensais d'utiliser l'objet du cache. Créez un objet Liste générique et enregistrez-le dans HttpContext.Cache et insérez-le à chaque nouvel élément. Cela ne fonctionnera pas car le CacheItemRemovedCallback se déclenchera immédiatement lorsque le HttpHandler essayera d'ajouter un nouvel élément. Je ne peux pas utiliser l'objet Cache comme file d'attente en mémoire.

Tout le monde peut suggérer quelque chose? Serais-je capable d'évoluer à l'avenir si la charge est plus?

Répondre

0

Que diriez-vous de simplement utiliser la liste générique pour stocker des demandes et utiliser un thread différent pour faire le SqlBulkCopy? De cette façon, le stockage des demandes dans la liste ne bloquera pas la réponse trop longtemps, et le thread d'arrière-plan sera capable de mettre à jour le Sql à son propre rythme, toutes les 5 min.

vous pouvez même baser le thread d'arrière-plan sur le mécanisme de cache en effectuant le travail sur CacheItemRemovedCallback.

Il suffit d'insérer un objet avec un temps de retrait de 5 min et de le réinsérer à la fin du traitement.

1

Pourquoi CacheItemRemovedCalledback se déclenche-t-il lorsque vous ajoutez un élément à la file d'attente? Cela n'a pas de sens pour moi ... Même si cela se déclenche, il n'y a aucune obligation de faire ici. Peut-être que je suis mal compris vos besoins?

J'ai assez bien utilisé l'objet Cache de cette manière. C'est pour ça que ça a été conçu et ça évolue plutôt bien. J'ai stocké un Hashtable qui a été consulté sur chaque demande de page d'application et mis à jour/effacé au besoin.

Option deux ... avez-vous vraiment besoin de la file d'attente? SQL Server évoluera plutôt bien si vous voulez écrire directement dans la base de données. Utilisez un objet de connexion partagé et/ou un pool de connexions.

0

Merci Alex & Bryan pour vos suggestions. Bryan: Lorsque j'essaie de remplacer l'objet List dans le cache pour la deuxième requête (maintenant, count devrait être 2), le CacheItemRemovedCalledback s'enflamme alors que je remplace l'objet Cache actuel par le nouveau. Au début, je pensais aussi que c'était un comportement bizarre, donc je dois y regarder de plus près. Aussi, pour la deuxième suggestion, je vais essayer d'insérer un enregistrement (avec l'objet SqlConnection mis en cache) et voir quelles sont les performances que je reçois lorsque je fais le stress test. Je doute que je reçoive des chiffres fantastiques car c'est une opération d'E/S.

Je vais continuer à creuser de mon côté pour une solution optimale en attendant avec vos suggestions.

+0

Si vous essayez d'insérer des enregistrements un par un, je doute que vous obteniez des performances acceptables. Ce que j'essayais de suggérer est de mettre à jour la base de données dans un volume, avec le nombre d'enregistrements. Jetez un oeil à SqlBulkCopy sur msdn. –

+0

Ah ... OK. Je pense que je vois votre problème maintenant. Vous n'avez pas besoin de replacer l'objet liste dans le cache à chaque requête! Il est là jusqu'à son expiration ou est explicitement supprimé. Utilisez simplement la même liste encore et encore. – Bryan

0

Vous pouvez créer une exigence conditionnelle dans la fonction de rappel pour vous assurer travaillez sur une entrée de cache qui a été frappé d'une expiration au lieu d'un supprimer/remplacer (en VB depuis que je l'avais à portée de main):

Private Shared Sub CacheRemovalCallbackFunction(ByVal cacheKey As String, ByVal cacheObject As Object, ByVal removalReason As Web.Caching.CacheItemRemovedReason) 
    Select Case removalReason 
     Case Web.Caching.CacheItemRemovedReason.Expired, Web.Caching.CacheItemRemovedReason.DependencyChanged, Web.Caching.CacheItemRemovedReason.Underused 
     ' By leaving off Web.Caching.CacheItemRemovedReason.Removed, this will exclude items that are replaced or removed explicitly (Cache.Remove) ' 
    End Select 
End Sub 

Modifier ici, il est en C# si vous en avez besoin:

private static void CacheRemovalCallbackFunction(string cacheKey, object cacheObject, System.Web.Caching.CacheItemRemovedReason removalReason) 
{ 
    switch(removalReason) 
    { 
     case System.Web.Caching.CacheItemRemovedReason.DependencyChanged: 
     case System.Web.Caching.CacheItemRemovedReason.Expired: 
     case System.Web.Caching.CacheItemRemovedReason.Underused: 
      // This excludes the option System.Web.Caching.CacheItemRemovedReason.Removed, which is triggered when you overwrite a cache item or remove it explicitly (e.g., HttpRuntime.Cache.Remove(key)) 
      break; 
    } 
} 
0

développiez mon commentaire précédent ... Je reçois l'image que vous pensez à la cache de manière incorrecte. Si vous avez un objet stocké dans le Cache, disons une Hashtable, toute mise à jour/stockage dans ce Hashtable sera conservé sans que vous ayez explicitement modifié le contenu du Cache. Vous n'avez besoin d'ajouter le Hashtable au cache qu'une seule fois, soit au démarrage de l'application, soit à la première demande.

Si vous êtes préoccupé par la mise à jour simultanée des demandes de bulkcopy et de demande de page, je vous suggère de disposer simplement de deux listes en cache. Avoir un être la liste qui est mise à jour lorsque les demandes de page entrent, et une liste pour l'opération de copie en bloc. Quand une copie en bloc est terminée, permutez les listes et répétez. Ceci est similaire à la RAM vidéo à double tampon pour les jeux vidéo ou les applications vidéo.

Questions connexes