.NET 2.0 a introduit la capacité de créer des providers simplement, tout en gérant assez finement la configuration. Ces fournisseurs (ie : 1 fournisseur = 1 implémentation d’une interface / contrat) sont configurables par un fichier .config (XML), et chargeables dynamiquement selon les besoins du client, en y introduisant une abstraction. Un exemple sur le MSDN comme point de départ.
du côté client
On va tenter à partir des providers de créer 2 fournisseurs :
- un cache local, basé sur le cache d’Asp.Net, ou bien sur le HttpRuntime1 dans le cas d’une assembly non contenue dans une application Web
- un cache distribué, basé sur Memcached, avec cette API. Il en existe 2 autres, non testées, EnyimMemcached et BeIT Memcached, cette dernière me paraissant très prometteuse.
Ces fournisseurs seront accessibles par un helper (classe statique), celui-ci encapsulant l’implémentation souhaitée (cache distribué ou local).
Le but est d’avoir une utilisation simple de cette classe :
// par défaut le cache local
CacheHelper.Add("cle","ma donnee",60000);
string val= CacheHelper.Get("cle") as string;
// utilisation du cache ditribué
CacheHelper.Strategy = "DistributedCacheProvider";
CacheHelper.Add("sharedkey","ma donnee a partager",60000);
string val2 = CacheHelper.Get("sharedkey") as string;
Je suis parti de ce code auquel j’ai ajouté la notion de stratégie, et de cet excellent article sur les mystères de la configuration .NET.
Chaque fournisseur, que nous appellerons AspNetcachedProvider et MemcachedProvider implémentent la classe abstraite ci-après, qui elle-même hérite de ProviderBase :
public abstract class CacheProvider : ProviderBase
{
public abstract long DefaultExpireTime { get;set;}
public abstract bool Add(string strKey, object objValue);
public abstract bool Add(string strKey, object objValue, bool bDefaultExpire);
public abstract bool Add(string strKey, object objValue, long lNumofMilliSeconds);
public abstract object Get(string strKey);
public abstract object Remove(string strKey);
}
Les providers sont définis dans un fichier de configuration (web.config, app.config ou fichier externe avec l’attribut possible configSource sur la section)
A titre d’exemple, on pourra avoir :
allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
servers="10.75.92.10:11211" socketConnectTimeout="1000" socketTimeout="1000"/>
Les fournisseurs sont instanciés lors de l’appel de CacheHelper. Cela permet de respecter le principe de Ouvert-Fermé. Ainsi, rien ne nous empêche d’avoir une autre implémentation pour le cache distribué, comme par exemple des données stockées par un serveur de bases de données ou bien une autre implémentation de Memcached (BeITMemcached). Il suffirait alors d’appeler cette implémentation au lieu de Memcached. En conséquence, la configuration se transformerait en :
allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
Découplé, souple, extensible, j’aime.
Quelques cas d’utilisation
Lorsqu’on utilise les pools d’applications, l’objet Cache n’est pas partagé entre les applications, le cache distribué est là le bienvenu.
Sur une plateforme avec des systèmes hétérogènes (Windows, Linux), partager des données entre plusieurs serveurs peut s’avérer utile, avoir un cache distribué est encore une fois bienvenue.
Enfin, on pourrait penser au besoin de partage d’objets entre une application (fenêtrée, service windows, ...) et une application Web.
Contraintes
Entre le cache local (utilisation de l’objet Cache) et Memcached, le comportement peut-être différent pour le stockage des objets. En effet, Cache permet de stocker n’importe quel objet, contrairement à Memcached qui nécessite que l’objet soit marqué de l’attribut [Serializable], sans quoi la sérialisation échouera.
du côté serveur
serveur memcached 1.2.4 sur Debian
Le package Debian est trop ancien (1.1x), il est préférable de partir des sources : 1.2.4 installée, la 1.2.5 vient de sortir. Il est nécessaire d’avoir libevent (apt-get install libevent-dev).
Suivre ce tutoriel
monitoring
Un plugin est disponible pour Munin afin de monitorer le serveur Memcached, prendre le plugin de 2ème génération.
Cela permet d’avoir des graphes de ce type :
memcached monitoring
memcached monitoring
serveur Windows
Une version Windows est disponible, non testée.
Sources
Le zip Caching.zip contient 3 répertoires :
- Caching : la librairie pour la gestion des 2 fournisseurs
- memcacheddotnet : l’implémentation Memcached, API v 1.1.5 trouvée sur Sourceforge
- Clients, scindé en CachingWebTest et CachingWinTest, 2 applications, Web et Winform qui utilisent le cache – en lançant les 2 en //, vous pourrez accéder à la même donnée partagée
Il suffit d’ouvrir la solution Caching.sln.
1 cela permettra d’utiliser l’objet Cache hors d’une application Web, par exemple dans une assembly, une application console, ...