Conseil en architecture C #: méthode pour mettre en cache des données dans une structure?

J’aimerais vous demander votre avis d’expert sur une architecture viable en C #.

J’ai un service C # qui répond à une demande d’un utilisateur local sur le réseau local, récupère des paquets de données sur Internet et les décompose pour produire des tableaux de données dans une structure. Chaque demande de données prend environ 2 secondes et renvoie 4000 octets. Il pourrait y avoir des dizaines de milliers de demandes par jour.

Pour accélérer le tout et réduire la bande passante, je dois mettre en cache les résultats du traitement des données afin que les access 2e et suivants soient servis instantanément à tous les autres utilisateurs du réseau (il pourrait y avoir plus de 50 utilisateurs).

Contraintes:

  1. Les données sous-jacentes ne changent jamais, c’est-à-dire que je n’ai pas à m’inquiéter des données “sales” (super!).
  2. Les données que je veux mettre en cache sont une structure plutôt complexe, contenant des tableaux nesteds DateTime, doubles, etc. Les données sont compressées à l’aide de nombreux calculs à partir des données fournies par Internet.
  3. Je ne peux pas utiliser plus de 100 Mo de mémoire, quelle que soit la quantité de données mise en cache (le cache doit avoir une taille limitée).
  4. Je ne peux pas indexer les données dans le cache avec un index numérique, je dois l’indexer avec une combinaison de date (“AAAA-MM-JJ”) et d’une chaîne d’identifiant unique (“XXXXXXXX”).
  5. Il doit être rapide, c’est-à-dire qu’il doit servir la plupart de ses réponses à partir de la RAM.
  6. Les données du cache doivent être conservées sur le disque toutes les 24 heures.

Voici mes options pour le moment:

  1. Cachez les données dans la classe de serveur, en utilisant des variables privées (liste privée ou dictionnaire), puis sérialisez-les à l’occasion sur le disque;
  2. Utiliser une firebase database;

Je suis intéressé par votre opinion d’expert.

De loin, la solution la plus simple consiste à utiliser un Dictionary pour cela.

Concernant vos besoins:

  1. La durée de vie du cache est plus facile à gérer car elle dispose d’un thread d’arrière-plan qui effectue une parsing du cache toutes les 10 minutes ou toutes les heures. Avec ComplexDataStructure , vous stockez un DateTime lors de la création du cache et supprimez la clé du dictionnaire une fois sa durée de vie écasting.

  2. Étant donné que vous stockez la structure de données réelle, la complexité n’est pas un problème;

  3. Limiter la taille peut être difficile. équivalent de sizeof () pour les types de référence? peut vous aider à calculer la taille de la structure de l’object. Cette opération ne sera pas anodine, mais vous pouvez stocker le résultat avec ComplexDataStructure . Ensuite, le même thread que celui utilisé pour 1. peut supprimer des entrées lorsque vous manquez d’espace. Une solution plus simple consisterait probablement à utiliser GC.GetTotalMemory() et à déterminer si l’utilisation totale de la mémoire par votre processus est en dehors d’une limite spécifique. Ensuite, supprimez simplement un élément de cache et, à la deuxième exécution, supprimez-en un lorsque vous constatez que vous utilisez encore trop de mémoire.

  4. Il suffit d’utiliser une ficelle;

  5. Utiliser le Dictionary<,> est probablement fatal à jeun;

  6. Encore une fois, utilisez le fil de 1. et implémentez une telle logique.

Assurez-vous de gérer correctement votre stratégie de locking. Le plus gros problème ici sera que vous ne voulez pas que le traitement soit insuffisant lorsqu’un autre thread traite déjà les données. Une solution à cela pourrait être la stratégie suivante:

  1. Verrouille le dictionnaire;

  2. Vérifiez si l’élément de cache existe;

  3. Lorsque l’élément de cache n’existe pas:

    1. Créer un élément de cache vide;

    2. Ajoutez cela au dictionnaire;

    3. Placez un verrou sur l’élément de cache.

    4. Relâchez le verrou sur le dictionnaire;

    5. Faites le traitement des données;

    6. Ajoutez les données écrasées à l’élément de cache.

    7. Libérez le verrou sur l’élément de cache;

  4. Lorsque l’élément de cache existe déjà;

    1. Lorsque l’élément de cache contient réellement les données compressées, renvoyez-les;

    2. Lorsque l’élément de cache n’a pas les données écrasées, verrouillez-le;

    3. À l’intérieur du verrou, les données croquantes seront apparues (car le verrou vous oblige à attendre sur l’autre thread).

Il y a d’autres problèmes à résoudre, mais je pense que les bases sont décrites ici.

Peut-être quelque chose comme Index4Objects?

( http://www.codeplex.com/i4o ) http://staxmanade.blogspot.com/2008/12/i4o-indexspecification-for.html

Aussi, lisez peut-être cette réponse à une autre question SO SO i4o vs. PLINQ .

Qu’en est-il: Utiliser les méthodes internes fournies par IIS?

Je pense avoir trouvé la solution idéale: bibliothèque de journalisation .NET PostSharp + Kellerman. PostSharp nécessite une légère courbe d’apprentissage (environ 15 minutes), mais une fois que vous êtes opérationnel, vous pouvez annoter votre méthode avec l’atsortingbut [Cachable] et le système mettra automatiquement en cache les résultats de cette méthode. C’est une solution aussi propre que possible.