2009-11-19 4 views
11

Nous travaillons sur une grande application héritée et nous sommes en train de reconcevoir la couche de gestion et la couche de données. Nous pensons que c'est le moment de revoir la façon dont le cache est géré. Existe-t-il des modèles et des meilleures pratiques pour implémenter une couche de mise en cache (ou la construire dans la couche de gestion)? Les seules choses auxquelles je peux penser sont d'utiliser la dépendance du cache SQL (ce qui est difficile car nous avons une grande base de données héritée avec beaucoup de tables qui ne correspondent pas toujours aux objets métier) et la mise en œuvre forte Tapez la classe CacheManager pour masquer les clés de chaîne et éliminer les problèmes de moulage de classe.Quels sont les modèles et les meilleures pratiques de mise en cache dans ASP.NET?

Y at-il quelque chose de plus sophistiqué que nous pouvons faire? Existe-t-il un moyen d'appliquer l'invalidation du cache lors de la mise à jour/suppression? Devrions-nous en quelque sorte maintenir un seul objet dans le cache et récupérer la liste des ID de la base de données qui fonctionnent toujours avec les mêmes objets?

Fondamentalement quelles techniques de mise en cache utilisez-vous dans ASP.NET? Dommage que nous ne pouvons pas utiliser des conteneurs IoC ou des cadres ORM qui prennent en charge le cache :(

Edit:. Je suis plus préoccupé par la maintenabilité que la performance

Répondre

17
  • Il suffit d'enregistrer tous les QueryResult à la base de données (avec la clé de cache: votre requête , la valeur: votre liste d'objets métier)
  • utilisation du cache distribué comme memcached à côté de cache ASP.Net
  • Utilisez un CacheManager sophistiqué comme https://github.com/enyim/memcached-providers, qui peuvent avoir cache-groupes Certaines données doivent être stockées pendant longtemps. , un peu de temps Certaines données doivent être stockées dans le cache ASP.Net, etc.
  • Effectuez les appels qui doivent être stockés dans le cache à l'aide d'une fonction wrapper comme public T GetFromCache<T>(string key, Func<T> ifKeyNotFoundDelegate) pour vous assurer que le cache est toujours utilisé de la même manière. [1]
  • Pensez à quand utiliser le cache ASP.Net et quand utiliser le cache distribué. Les données lues à chaque requête doivent être stockées dans ASP.Net, les données volumineuses telles que les résultats de recherche; avec beaucoup de différentes clés et de données, etc. devrait être en memcached.
  • Ajouter un versionnage. Préfixez toutes les clés avec un numéro de version, de sorte que vous n'ayez pas de problème lors de la mise à jour de votre application Web, et que certains contrats d'objet changent.

Eh bien, cela couvre la plupart de ce que nous faisons dans notre site Web (20 Go memcached cluster répartis sur 20 serveurs). [1] En faisant d'une telle fonction la seule interface pour stocker des choses dans le cache, vous pouvez obtenir ce qui suit. Disons que je veux utiliser quelque chose du cache, comme le résultat d'une fonction. Normalement vous feriez quelque chose comme

CacheManager cm = new CacheManager(CacheGroups.Totals); 
object obj = cm.GetFromCache("function1result"); 
if(obj == null) 
{ 
    obj = (object)DAO.Foo(); 
    cm.StoreInCache("function1result", obj); 
} 
return (List<MyEntity>)obj; 

En utilisant une interface différente, vous pouvez vous assurer que les utilisateurs ne feront pas d'erreur ici.

Comme

public T GetFromCache<T>(string key, Func<T> ifnotfound) 
{ 
    T obj = this.GetFromCache(key) as T; 
    if(obj == default(T)) 
    { 
     obj = ifnotfound.Invoke(); 
     this.StoreInCache(key, obj); 
    } 
    return obj; 
} 

Cela garantit que

  1. Nous avons toujours travailler avec le bon type
  2. Que votre utilisateur travaille toujours avec le cache de la même manière

Ergo: moins probable qu'ils font une erreur. De plus vous obtenez plus agréable, plus clair, le code, comme:

List<MyEntity> list = new CacheManager(CacheGroups.Total).GetFromCache<List<MyEntity>>("function1result",()=>DAO.Foo()); 
+0

Merci beaucoup (et tout le monde qui a répondu). Pouvez-vous élaborer sur ceci: • Faire des appels qui doivent être stockés dans le cache en utilisant une fonction wrapper publique T GetFromCache (clé de chaîne, Func ifKeyNotFoundDelegate) pour s'assurer que le cache est toujours utilisé le même. – Stilgar

+1

Dans un environnement multithread, n'oubliez pas un verrou dans GetFromCache <>(). – RickNZ

1

L'équipe Modèles et pratiques MS Enterprise Library créé leur réponse à cette question pour toute une série de scénarios de Commone. EntLib inclut la mise en cache ainsi que l'accès aux données, la validation, la journalisation, la gestion des exceptions, etc. Nous l'utilisons depuis des années et ne penserions pas à démarrer un nouveau projet sans cela.

http://www.codeplex.com/entlib

Outre le P & P page d'accueil, http://msdn.microsoft.com/en-us/practices/default.aspx

+0

Bloc d'application de mise en cache exclu de la bibliothèque d'entreprise 6, ils ont décidé de retirer certains blocs d'EntLib, comme décrit [ici] (http://msdn.microsoft.com/fr-fr/library/dn169621.aspx#WhatsNew) –

3

C'est un grand sujet, mais voici quelques suggestions:

  1. Ne pas les données de cache qui est peu probable à réutiliser, telles que des données spécifiques à l'utilisateur
  2. Cache à tous les niveaux: client, Silverlight (stockage isolé), proxies, http.sys, IIS, objet cache ASP.NET, ASP.NET p er-request cache, SQL Server
  3. Utilisez SqlDependency/SqlCacheDependency lorsque vous le pouvez, mais ne l'utilisez pas trop
  4. Évitez l'état de session; utiliser des cookies à la place quand vous pouvez
  5. la page Effet de levier et de contrôle (fragment) la mise en cache de sortie
  6. Envisagez d'utiliser la validation du cache en cas de besoin
  7. Tenir compte des alternatives légères à l'objet de cache ASP.NET, comme refs mémoire faibles
  8. Lorsqu'ils sont utilisés correctement, SQL Server peut agir comme un grand cache

dans le cas où il aide, je couvre ce sujet en détail dans mon livre: Ultra-Fast ASP.NET.

+0

vous voulez dire par refs mémoire faible?Une forme de mise en cache très simple que j'utilise est de créer une variable statique comme ceci: private static DataTable _products; produits DataTable statiques publics {get { if (_productes == null) {_ produits = getProductsFromSQLServer();} retour _PRODUITS }} Est-ce casher? Je ne le fais habituellement que pour de très petits ensembles d'enregistrements. –

+0

Wow, désolé à ce sujet. Tout mon espace blanc a été retiré du commentaire. –

+0

@ J.Hendix: Pour plus d'informations sur les références mémoire faibles, consultez la classe WeakReference (ou postez peut-être une question sur StackOverflow). Votre exemple était une référence statique forte. C'est certainement une forme valide de mise en cache. L'avantage d'un ref faible est que le GC peut le lâcher si la pression de la mémoire devient trop élevée, alors qu'il ne peut pas lâcher un ref fort. – RickNZ

Questions connexes